Wpf 多绑定转换回问题

Wpf 多绑定转换回问题,wpf,multibinding,imultivalueconverter,Wpf,Multibinding,Imultivalueconverter,为了解决我在另一个项目中遇到的问题,我创建了以下示例来复制这个问题 其思想是,当用户通过滑块或文本框输入新值时,这些值应通过转换器“转换回”,并更新源。但我似乎没有看到这一点,我认为这是因为InternalRep的属性正在写入,但没有通知InternalRepProperty的bindexpression 解决这个问题的最好办法是什么 我尝试的一种方法是处理sliders ValueChanged事件,但这导致转换器。。。ConvertBack然后ConvertBack然后ConvertBack

为了解决我在另一个项目中遇到的问题,我创建了以下示例来复制这个问题

其思想是,当用户通过滑块或文本框输入新值时,这些值应通过转换器“转换回”,并更新源。但我似乎没有看到这一点,我认为这是因为InternalRep的属性正在写入,但没有通知InternalRepProperty的bindexpression

解决这个问题的最好办法是什么

我尝试的一种方法是处理sliders ValueChanged事件,但这导致转换器。。。ConvertBack然后ConvertBack然后ConvertBack然后ConvertBack,不知道为什么

当用户更改一个值时,我只需要ConvertBack来更新源代码,而不需要其他任何东西。。这可能吗

文本拆分器XAML

<ContentControl x:Class="WpfApplication23.TextSplitter"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:local="clr-namespace:WpfApplication23"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">

    <UniformGrid Columns="3" Rows="2">
        <TextBox Text="{Binding RelativeSource={RelativeSource AncestorType={x:Type local:TextSplitter}}, 
                 Path=InternalRep.First, UpdateSourceTrigger=PropertyChanged, Mode=TwoWay}" />

        <TextBox Text="{Binding RelativeSource={RelativeSource AncestorType={x:Type local:TextSplitter}}, 
                 Path=InternalRep.Second, UpdateSourceTrigger=PropertyChanged, Mode=TwoWay}" />

        <TextBox Text="{Binding RelativeSource={RelativeSource AncestorType={x:Type local:TextSplitter}}, 
                 Path=InternalRep.Third, UpdateSourceTrigger=PropertyChanged, Mode=TwoWay}" />

        <Slider  Value="{Binding RelativeSource={RelativeSource AncestorType={x:Type local:TextSplitter}}, 
                 Path=InternalRep.First, UpdateSourceTrigger=PropertyChanged, Mode=TwoWay}" Maximum="255" />

        <Slider  Value="{Binding RelativeSource={RelativeSource AncestorType={x:Type local:TextSplitter}}, 
                 Path=InternalRep.Second, UpdateSourceTrigger=PropertyChanged, Mode=TwoWay}" Maximum="255" />

        <Slider  Value="{Binding RelativeSource={RelativeSource AncestorType={x:Type local:TextSplitter}}, 
                 Path=InternalRep.Third, UpdateSourceTrigger=PropertyChanged, Mode=TwoWay}" Maximum="255" ValueChanged="OnSliderChnaged" />
    </UniformGrid>

</ContentControl>
主窗口XAML

<Window x:Class="WpfApplication23.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:local="clr-namespace:WpfApplication23"
        Title="MainWindow" Height="640" Width="800" WindowStartupLocation="CenterScreen">
    <StackPanel>
        <local:TextSplitter First="{Binding A, Mode=TwoWay}"
                            Second="{Binding B, Mode=TwoWay}"
                            Third="{Binding C, Mode=TwoWay}"/>
    </StackPanel>
</Window>

您需要在ViewModel中实现INotifyPropertyChanged。
在这里,ViewModel是窗口,因此您必须执行以下操作:

public partial class MainWindow : Window, INotifyPropertyChanged
{
    public MainWindow()
    {
        this.DataContext = this;
        InitializeComponent();
    }

    char m_a = 'a';
    public char A
    {
        get { return m_a; }
        set
        {
            if (value != m_a)
            {
                m_c = value;
                RaisePropertyChanged("A");
            }
        }
    }

    char m_B = 'b';
    public char B
    {
        get { return m_B; }
        set
        {
            if (value != m_B)
            {
                m_c = value;
                RaisePropertyChanged("B");
            }
        }
    }

    char m_c = 'c';
    public char C
    {
        get { return m_c; }
        set
        {
            if (value != m_c)
            {
                m_c = value;
                RaisePropertyChanged("C");
            }
        }
    }

    public event PropertyChangedEventHandler PropertyChanged;
    private void RaisePropertyChanged(string _Prop)
    {
        if (PropertyChanged != null)
        {
            PropertyChanged(this, new PropertyChangedEventArgs(_Prop));
        }
    }

    DelegateCommand _RecomputeCommand;
    public DelegateCommand RecomputeCommand
    {
        get { return _RecomputeCommand ?? (_RecomputeCommand = new DelegateCommand(Recompute)); }
    }

    public void Recompute()
    {
        //Do something with A, B and C.
    }
}
编辑:您只需将3个滑块绑定到A、B、C(您需要上述实现),然后根据重新计算的命令执行操作,如下所示:

<StackPanel>
    <Slider Value="{Binding A}" Maximum="255">
        <i:Interaction.Triggers>
            <i:EventTrigger EventName="ValueChanged">
                <i:InvokeCommandAction Command="{Binding RecomputeCommand}" />
            </i:EventTrigger>
        </i:Interaction.Triggers>
    </Slider>
    <Slider Value="{Binding B}" Maximum="255">
        <i:Interaction.Triggers>
            <i:EventTrigger EventName="ValueChanged">
                <i:InvokeCommandAction Command="{Binding RecomputeCommand}" />
            </i:EventTrigger>
        </i:Interaction.Triggers>
    </Slider>
    <Slider Value="{Binding C}" Maximum="255">
        <i:Interaction.Triggers>
            <i:EventTrigger EventName="ValueChanged">
                <i:InvokeCommandAction Command="{Binding RecomputeCommand}" />
            </i:EventTrigger>
        </i:Interaction.Triggers>
    </Slider>
</StackPanel>


当然,这可以根据需要在
ContentControl
中执行。

我看不出这对我有什么帮助,问题是这些值一开始没有被写回源代码。转换是单向的,通过将源转换为目标。。但是,当用户更改目标时,源不存在updated@wforl如果你不筹集财产,你如何得到通知?无论何时编写
绑定
,路径必须指向PropertyChanged ready属性,否则只能在初始化时检索该值。@baboon。问题不在于正在检索的值。。我真的希望只有在初始化时才能读到。问题是TextSplitterControl没有写回MainWindow.A | MainWindow.B | MainWindow。C@wforl你试过我的解决方案吗?我试过了,但没有解决我的问题。也许我不清楚我在追求什么。当用户与滑块/文本框交互时,我希望主窗口中的属性A、B、C的设置器被调用。如果一开始没有调用setter,您的解决方案将如何更改任何内容?当文本框/滑块中的值正在更改时,不会调用ConvertBack函数。您的
onSliderManaged
方法做什么?由于您有双向绑定,
ConvertBack
将被调用一次,因此在
ValueChanged
事件中第二次调用它将使其运行两次。此外,我仍在试图找出代码隐藏中的
多重绑定
,但也有可能使其运行两次。OnSliderManaged方法没有实现,它只是一些实验的结果,整个应用程序如我上面所述。问题是,当用户编辑滑块/文本框时,convertback永远不会被调用,这就是我试图解决的问题/remedy我开始认为存在架构问题。通过让二传手被叫来,你到底想达到什么目的?当绑定到一个变量的一个滑块发生变化时,为什么要调用所有3个setter?你在计算吗?我发布的示例代码就是为了演示我在多绑定中遇到的问题。所有三个设置器都将在convertback中调用,因为这是多转换器的工作方式,不是吗?
public partial class MainWindow : Window, INotifyPropertyChanged
{
    public MainWindow()
    {
        this.DataContext = this;
        InitializeComponent();
    }

    char m_a = 'a';
    public char A
    {
        get { return m_a; }
        set
        {
            if (value != m_a)
            {
                m_c = value;
                RaisePropertyChanged("A");
            }
        }
    }

    char m_B = 'b';
    public char B
    {
        get { return m_B; }
        set
        {
            if (value != m_B)
            {
                m_c = value;
                RaisePropertyChanged("B");
            }
        }
    }

    char m_c = 'c';
    public char C
    {
        get { return m_c; }
        set
        {
            if (value != m_c)
            {
                m_c = value;
                RaisePropertyChanged("C");
            }
        }
    }

    public event PropertyChangedEventHandler PropertyChanged;
    private void RaisePropertyChanged(string _Prop)
    {
        if (PropertyChanged != null)
        {
            PropertyChanged(this, new PropertyChangedEventArgs(_Prop));
        }
    }

    DelegateCommand _RecomputeCommand;
    public DelegateCommand RecomputeCommand
    {
        get { return _RecomputeCommand ?? (_RecomputeCommand = new DelegateCommand(Recompute)); }
    }

    public void Recompute()
    {
        //Do something with A, B and C.
    }
}
<StackPanel>
    <Slider Value="{Binding A}" Maximum="255">
        <i:Interaction.Triggers>
            <i:EventTrigger EventName="ValueChanged">
                <i:InvokeCommandAction Command="{Binding RecomputeCommand}" />
            </i:EventTrigger>
        </i:Interaction.Triggers>
    </Slider>
    <Slider Value="{Binding B}" Maximum="255">
        <i:Interaction.Triggers>
            <i:EventTrigger EventName="ValueChanged">
                <i:InvokeCommandAction Command="{Binding RecomputeCommand}" />
            </i:EventTrigger>
        </i:Interaction.Triggers>
    </Slider>
    <Slider Value="{Binding C}" Maximum="255">
        <i:Interaction.Triggers>
            <i:EventTrigger EventName="ValueChanged">
                <i:InvokeCommandAction Command="{Binding RecomputeCommand}" />
            </i:EventTrigger>
        </i:Interaction.Triggers>
    </Slider>
</StackPanel>