Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/269.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# XAML/C如何创建具有一个源和多个目标的双向绑定?_C#_Wpf_Xaml_Data Binding_Uwp - Fatal编程技术网

C# XAML/C如何创建具有一个源和多个目标的双向绑定?

C# XAML/C如何创建具有一个源和多个目标的双向绑定?,c#,wpf,xaml,data-binding,uwp,C#,Wpf,Xaml,Data Binding,Uwp,我想用三个文本框定义一个时间跨度;一个小时,分,秒。数据验证超出了我的问题范围 我在xaml中定义了三个文本框: <UserControl x:Class="Test_Timer.Timer" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:local="

我想用三个文本框定义一个时间跨度;一个小时,分,秒。数据验证超出了我的问题范围

我在xaml中定义了三个文本框:

<UserControl
    x:Class="Test_Timer.Timer"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:local="using:Test_Timer"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    mc:Ignorable="d"
    x:Name="timer">
    <StackPanel Orientation="Horizontal>
        <TextBox x:Name="hoursBox" />
        <TextBlock Text=":" />
        <TextBox x:Name="minutesBox" />
        <TextBlock Text=":" />
        <TextBox x:Name="secondsBox" />
    </StackPanel>
</UserControl>
如何在三个文本框和Duration属性之间设置双向绑定

将转换器定义为网格中的静态资源,然后将文本框与转换器和转换器参数绑定到持续时间

convert方法从viewModel属性获取数据,并根据需要进行转换,然后将数据返回到UI文本框

convertback方法从文本框中获取数据并进行转换,然后将其发送到viewmodel属性

我已经向您展示了如何实现这一目标。您只需要弄清楚如何处理convert-back方法,我在这里编写的代码从textbox获取一个字符串,并根据它是否来自哪个textbox ConverterParameter帮助我们,相应地将than-strong转换为TimeSpan对象,然后使用return语句将其指定给viewmodel Duration属性。现在由您决定在将它们发送到Duration之前如何组合它们

暗示

根据您的场景,您需要以某种方式组合小时、分钟和秒,然后将其分配给viewmodel的持续时间。所以我建议一种可能的方法

创建一个可以保存3个静态属性的公共静态类,它们将在Convert和ConvertBack方法中不断更新,这将有助于您进行组合

public static class DurationValues
{
    public static string Hours="";
    public static string Minutes="";
    public static string Seconds="";
}
并具有如下所示的convert类

public class DurationFormatter : IValueConverter
{
    public object Convert(object value, Type targetType, 
        object parameter, string language)
    {
        string formatString = parameter as string;
        if (formatString == "hoursBox")
        {
            string rValue = ((TimeSpan)value).Hours.ToString();
            DurationValues.Hours=rValue;
            return rValue;
        }
        else if (formatString == "minutesBox")
        {
            string rValue = ((TimeSpan)value).Minutes.ToString();
            DurationValues.Minutes=rValue;
            return rValue;
        }
        else
        {
            string rValue = ((TimeSpan)value).Seconds.ToString();
            DurationValues.Seconds=rValue;
            return rValue;
        }
    }

    public object ConvertBack(object value, Type targetType, 
        object parameter, string language)
    {
        string formatString = parameter as string;
        if (formatString == "hoursBox")
        {
            DurationValues.Hours = (string)value;
            var ts = new TimeSpan (DurationValues.Hours,DurationValues.Minutes,DurationValues.Seconds);
            return ts;
        }
        else if (formatString == "minutesBox")
        {
            DurationValues.Minutes = (string)value;
            var ts = new TimeSpan (DurationValues.Hours,DurationValues.Minutes,DurationValues.Seconds);
            return ts;
        }
        else
        {
            DurationValues.Seconds = (string)value;
            var ts = new TimeSpan (DurationValues.Hours,DurationValues.Minutes,DurationValues.Seconds);
            return ts;
        }
    }
}
IValueConverter的另一个示例:


这是我最终得到的解决方案,99%的灵感来自于Tuseefbsb的答案

以下是XAML:

<UserControl
    x:Class="Test_Timer.Timer"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:local="using:Test_Timer"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    mc:Ignorable="d"
    x:Name="timer">
    <UserControl.Resources>
        <local:TimeSpanConverter x:Key="TimeSpanConverter" />
    <UserControl.Resources>
    <Grid>
        <StackPanel Orientation="Horizontal>            
            <TextBox x:Name="hoursBox" Text="{Binding vm.Duration, Mode=TwoWay,
                        Converter={StaticResource TimeSpanConverter}, 
                        ConverterParameter=hours}"/>
            <TextBlock Text=":" />
            <TextBox x:Name="minutesBox" Text="{Binding vm.Duration, Mode=TwoWay,
                        Converter={StaticResource TimeSpanConverter}, 
                        ConverterParameter=minutes}"/>
            <TextBlock Text=":" />
            <TextBox x:Name="secondsBox" Text="{Binding vm.Duration, Mode=TwoWay,
                        Converter={StaticResource TimeSpanConverter}, 
                        ConverterParameter=seconds}"/>
        </StackPanel>
    </Grid>
</UserControl>

请注意,我需要为每个计时器使用不同的转换器实例,因为我依赖于小时、分钟和秒属性。

wpf和uwp是两个独立的平台,请仅为应用程序所在的平台添加相应的标记。@tuseefbsb xaml和绑定组件在uwp和wpf之间是通用的。由于我的问题主要涉及绑定,我相信它适用于这两个平台,并且很乐意接受使用其中一个平台的答案。但是,注意到您的观点,我将更改标题以删除UWP。您是否尝试将每个文本框绑定到嵌套属性,如“Duration.Hours”到“Hours”文本框,等等?TimeSpan上的小时、分钟和秒属性是只读的。我想我需要先做一些处理来合并它们。可能只是需要在代码隐藏中完成的情况之一。这真的有效吗?您可以组合这3个属性并创建一个设置了小时、分钟和秒的TimeSpan,还是每次都创建一个新的TimeSpan?它每次都在ConvertBack方法中创建一个新的TimeSpan,如何组合这3个属性实际上取决于您的场景,您必须弄清楚这一点。这是一个好的开始。它确实解决了从Duration属性更新文本框的问题。但正如您所提到的,它并不能解决如何将文本框属性组合成持续时间的问题。我不知道你为什么认为这件事取决于情节。你能详细说明一下吗?我预见到的问题是,我们在转换器中一次只能访问一个文本框值,因此,无法将这三种属性结合起来。@SimCard我更新了我的答案,并添加了一个建议,说明了一种实现所需目标的方法。我之所以说这取决于场景,是因为您在问题中表示不希望在viewmodel中使用三种不同的属性,因为这实际上改变了我们实现它的方式。
public static class DurationValues
{
    public static string Hours="";
    public static string Minutes="";
    public static string Seconds="";
}
public class DurationFormatter : IValueConverter
{
    public object Convert(object value, Type targetType, 
        object parameter, string language)
    {
        string formatString = parameter as string;
        if (formatString == "hoursBox")
        {
            string rValue = ((TimeSpan)value).Hours.ToString();
            DurationValues.Hours=rValue;
            return rValue;
        }
        else if (formatString == "minutesBox")
        {
            string rValue = ((TimeSpan)value).Minutes.ToString();
            DurationValues.Minutes=rValue;
            return rValue;
        }
        else
        {
            string rValue = ((TimeSpan)value).Seconds.ToString();
            DurationValues.Seconds=rValue;
            return rValue;
        }
    }

    public object ConvertBack(object value, Type targetType, 
        object parameter, string language)
    {
        string formatString = parameter as string;
        if (formatString == "hoursBox")
        {
            DurationValues.Hours = (string)value;
            var ts = new TimeSpan (DurationValues.Hours,DurationValues.Minutes,DurationValues.Seconds);
            return ts;
        }
        else if (formatString == "minutesBox")
        {
            DurationValues.Minutes = (string)value;
            var ts = new TimeSpan (DurationValues.Hours,DurationValues.Minutes,DurationValues.Seconds);
            return ts;
        }
        else
        {
            DurationValues.Seconds = (string)value;
            var ts = new TimeSpan (DurationValues.Hours,DurationValues.Minutes,DurationValues.Seconds);
            return ts;
        }
    }
}
<UserControl
    x:Class="Test_Timer.Timer"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:local="using:Test_Timer"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    mc:Ignorable="d"
    x:Name="timer">
    <UserControl.Resources>
        <local:TimeSpanConverter x:Key="TimeSpanConverter" />
    <UserControl.Resources>
    <Grid>
        <StackPanel Orientation="Horizontal>            
            <TextBox x:Name="hoursBox" Text="{Binding vm.Duration, Mode=TwoWay,
                        Converter={StaticResource TimeSpanConverter}, 
                        ConverterParameter=hours}"/>
            <TextBlock Text=":" />
            <TextBox x:Name="minutesBox" Text="{Binding vm.Duration, Mode=TwoWay,
                        Converter={StaticResource TimeSpanConverter}, 
                        ConverterParameter=minutes}"/>
            <TextBlock Text=":" />
            <TextBox x:Name="secondsBox" Text="{Binding vm.Duration, Mode=TwoWay,
                        Converter={StaticResource TimeSpanConverter}, 
                        ConverterParameter=seconds}"/>
        </StackPanel>
    </Grid>
</UserControl>
class TimeSpanConverter : IValueConverter
{
    public int Hours { get; set; }

    public int Minutes { get; set; }

    public int Seconds { get; set; }

    public object Convert(object value, Type targetType, object parameter, string language)
    {
        string strParam = (string)parameter;
        TimeSpan ts = (TimeSpan)value;

        switch(strParam.ToLower())
        {
            case "hours":
                return ts.Hours.ToString();
            case "minutes":
                return ts.Minutes.ToString();
            case "seconds":
                return ts.Seconds.ToString();
        }
        return "0";
    }

    public object ConvertBack(object value, Type targetType, object parameter, string language)
    {
        string strParam = (string)parameter;
        int intVal = int.Parse((string)value);

        switch (strParam.ToLower())
        {
            case "hours":
                Hours = intVal;
                break;
            case "minutes":
                Minutes = intVal;
                break;
            case "seconds":
                Seconds = intVal;
                break;
        }

        return new TimeSpan(Hours, Minutes, Seconds);
    }
}