【问题标题】:MultiValueConverter - NotifyPropertyChangedMultiValueConverter - NotifyPropertyChanged
【发布时间】:2014-05-01 21:08:39
【问题描述】:

对我的要求有一点烦人的问题,希望可以解决。

假设您有以下类:

public class Foo
{
    public string Name { get; set; }
    public List<FooB> FooBs { get; set; }
}

public class FooB
{
    public int Id1 { get; set; }
    public int Id2 { get; set; }
    public decimal Sum { get; set; }
}

现在Foo 类有一个FooB 列表,其中包含给定Id1Id2 值和一个Sum 计算值。

在我的 WPF 用户界面中,我有 2 ComboBoxes1 DataGrid。 1 个 ComboBox 包含有关 Id1 的信息,另一个包含有关 Id2 的信息。

现在在我的 DataGrid 中,我有一个 Foo 列表,其中显示了 2 列,其中一个显然是名称,但另一个现在让我很头疼。

第二列应显示"correct" FooB 类的Sum 属性。

正确的 FooB 类由 UI 中的 2 个 ComboBox 和 SelectedItem 确定。

到目前为止,我所做的是在我的 CodeBehind 中创建 2 个属性:(请注意,它们实际上有支持字段和 PropertyChanged 指定我将代码简化为我的主要问题)

public int SelectedId1 { get; set; }
public int SelectedId2 { get; set; }

这两个属性绑定到对应的ComboBox:

<c1:C1ComboBox ItemsSource="{Binding Id1s}"
                SelectedItem="{Binding SelectedId1}" />
<c1:C1ComboBox ItemsSource="{Binding Id2s}"
                SelectedItem="{Binding SelectedId2}" />

到目前为止,我的 DataGrid 如下所示:

<local:BindingProxy x:Key="BindingProxy"
                    Data="{Binding}" />

<DataGrid ItemsSource={Bindings Foos}>
    <DataGrid.Columns>
        <DataGridTextColumn Binding="{Binding Name}" />
        <DataGridTextColumn>
            <DataGridTextColumn.Binding>
                <MultiBinding Converter="{StaticResource GetCorrectFooB}">
                    <Binding Binding="."></Binding>
                    <Binding Binding="Data.SelectedId1"></Binding>
                    <Binding Binding="Data.SelectedId2"></Binding>
                </MultiBinding>
            </DataGridTextColumn.Binding>
        </DataGridTextColumn>
    </DataGrid.Columns>
</DataGrid>

(请注意 BindingProxy 来自此处:http://www.thomaslevesque.com/2011/03/21/wpf-how-to-bind-to-data-when-the-datacontext-is-not-inherited/ - 以启用从 DataGridRow 的 DataContext 中的窗口获取数据)

转换器如下所示:

public class GetCorrectFooB : IMultiValueConverter
{
    public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture)
    {
        var foo = (Foo)values[0];
        var id1 = (int) values[1];
        var id2 = (int) values[2];

        return foo.FooBs.First(x => x.Id1 == id1 && x.Id2 == id2).Sum;
    }

    public object[] ConvertBack(object value, Type[] targetTypes, object parameter, CultureInfo culture)
    {
        throw new NotImplementedException();
    }
}

这目前工作得很好,甚至当我在 UI 中更改 2 个 ComboBoxes 中的值并相应地更新信息时表现正确但是......当底层 Sum PropertyChanges 并且收到 PropertyChanges 的通知时,UI 没有更新。

如果我只是将列绑定到它,它工作正常

<DataGridTextColumn Binding="{Binding FooBs[12].Sum}" />

你可以想象我不想在那里有一个索引,因为我需要通过 UI 中的 ComboBoxes 来更新它。

希望你能帮帮我。

【问题讨论】:

    标签: c# wpf datagrid combobox multibinding


    【解决方案1】:

    首先,我很难理解您当前的绑定表达式实际上是如何呈现 sum,因为您的 converter 似乎只是返回 FooB 对象本身,而不是它的 sum 属性 - 所以除非你的 FooB 类上有一个特定的 ToString() 实现格式化它以呈现 sum,我完全迷失了。

    其次,我认为您的问题源于您的 MultiBinding 仅基于两个属性 - Data.SelectedId1Data.SelectedId2,因此,除非这两个属性中的任何一个发生更改,否则 MultiBinding 将不会接收 PropertyChanged 事件并进行更新。

    结果的 sum 属性值的变化不是这两者,因此这很可能是视图未更新的原因。

    我绞尽脑汁想解决这个问题,也许你应该在 ViewModel 中处理这个问题,有一个名为 CurrentFooB 的属性或者你可以绑定的东西。然后,您可以将此值设置为组合框的 SelectionChanged 事件处理程序中相应的 FooB 实例。

    您的绑定将如下所示:

    <DataGrid ItemsSource={Binding Foos}>
    
        <DataGrid.Columns>
    
            <DataGridTextColumn Binding="{Binding Name}"/>
            <DataGridTextColumn Binding="{Binding CurrentFooB.Sum}"/>
    
        </DataGrid.Columns>
    
    </DataGrid>
    

    现在,如果 FooB 实现了 INotifyPropertyChanged,那么当当前找到的 FooBsum 发生变化时,您的视图应该会更新。

    EDIT 1(尝试动态设置绑定源):

    <DataGrid ItemsSource={Binding Foos}>
    
        <DataGrid.Columns>
    
            <DataGridTextColumn Binding="{Binding Name}"/>
            <DataGridTextColumn>
    
                <DataGridTextColumn.Binding>
    
                    <Binding Path="Sum">
    
                        <Binding.Source>
    
                            <MultiBinding Converter="{StaticResource GetCorrectFooB}">
                                <Binding Binding="."></Binding>
                                <Binding Binding="Data.SelectedId1"></Binding>
                                <Binding Binding="Data.SelectedId2"></Binding>
                            </MultiBinding>
    
                        </Binding.Source>
    
                    </Binding>
    
                </DataGridTextColumn.Binding>
    
            </DataGridTextColumn>
    
        </DataGrid.Columns>
    
    </DataGrid>
    

    【讨论】:

    • 是的,你是对的,在我的示例中,我没有提供有关如何获得 Sum 属性的信息,对此感到抱歉。在我的现实应用程序中,我尝试了两种方式,使用.ToString() 并在转换器中传递.Sum 属性,两者都没有你已经解释过的运气。你是说我需要为Foo 提供一个CurrentFooB 属性并使用正确的FooB 更新网格中的所有实例?
    • 我有点希望有一种方法,可以通过绑定中的源属性获取对象,或者我不知道......并且只需指定求和的路径。或者在绑定中有一个多重绑定,以便源/数据上下文可以通过多重绑定来绑定以获得正确的 FooB,并且绑定本身只是指定路径...一些在构建 WPF/XAML 的东西中没有代码隐藏。
    • 是的,我明白你的担忧,我相信一定有办法。在我的脑海中......呃......如果你可以使用你当前的 MultiBinding 来设置另一个绑定到 Sum 属性的 DataContext 怎么办?
    • 这样就可以了,不是吗?由于 DataContext 将是 FooB 的实例,并且 Binding 将提供 DataContext 的路径,因此当 Sum 收到关于 propertychanged 的​​通知时。底层 DataBinding 会检查“嘿,我的 DataContext 是 FooB,我的路径是 Sum 所以更新”,但这只是疯狂的想象,因为没有嵌套的 Bind --> MultiBinding。像&lt;Binding&gt; &lt;Binding.DataContext&gt; &lt;MultiBinding&gt; &lt;Binding /&gt; &lt;Binding /&gt; &lt;/MultiBinding&gt; &lt;/Binding.DataContext&gt; &lt;/Binding&gt; 这样的东西。或&lt;Binding.Source&gt;
    • 希望如此! :P 检查我编辑的答案,我刚刚意识到使用 Binding 的 Source 属性而不是 DataContext 可能会更好。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-04-25
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多