在DataGridCell上更新MultiBinding [英] Update MultiBinding on DataGridCell

查看:73
本文介绍了在DataGridCell上更新MultiBinding的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在通过 MultiBinding IMultiValueConverter 在应用程序中集成属性更改检测。因此,当用户更改 DataGrid时, DataGridCell将更改背景颜色。我的问题是,当用户保存工作时,如果没有屏幕闪烁,我将无法删除更改的背景。我可以这样做 DataContext = null 然后 DataContext = this`,但它会导致屏幕闪烁。我不能调用更新绑定将MultiBinding重置为默认值。

I am integrating property change detection in an application by way of MultiBinding and IMultiValueConverter. So when a user makes changes to a 'DataGrid', the DataGridCell' changes background color. My issue is that when the user saves their work I cannot remove the changed background without a screen flicker. I can doDataContext = nullthenDataContext = this` but it causes a screen flicker. I cannot call an update binding to reset the MultiBinding to default.

问:如何在如下所示的DataGridCell上更新MultiBinding?

Q: How can I update the MultiBinding on a DataGridCell like below?

很遗憾,这不是MVVM。我创建了一个显示问题的项目: https://github.com/jmooney5115/clear-multibinding

Unfortunately this is not MVVM. I created a project that shows the issue: https://github.com/jmooney5115/clear-multibinding

此解决方案适用于TextBox,但不适用于DataGridCell:

This solution works for TextBox but not DataGridCell:

foreach (TextBox textBox in FindVisualChildren<TextBox>(this))
{
    multiBindingExpression = BindingOperations.GetMultiBindingExpression(textBox, TextBox.BackgroundProperty);
    multiBindingExpression.UpdateTarget();
}

这是数据网格单元格的多重绑定。原始值和修改后的值。如果更改该值,则返回true,以将背景色设置为LightBlue。如果为false,则背景为默认颜色。

This is the multi binding for a data grid cell The multi value converter takes the original value and the modified value. If the value is changed it returns true to set the background color to LightBlue. If false, the background is the default color.

<DataGrid.Columns>
    <DataGridTextColumn Header="Destination Tag name" Binding="{Binding Path=Name, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" >
        <!-- https://stackoverflow.com/questions/5902351/issue-while-mixing-multibinding-converter-and-trigger-in-style -->
        <DataGridTextColumn.CellStyle>
            <Style TargetType="{x:Type DataGridCell}">
                <Style.Triggers>
                    <DataTrigger Value="True">
                        <DataTrigger.Binding>
                            <MultiBinding Converter="{StaticResource BackgroundColorConverterBool}">
                                <Binding Path="Name"    />
                                <Binding Path="Name" Mode="OneTime" />
                            </MultiBinding>
                        </DataTrigger.Binding>
                    </DataTrigger>

                    <Setter Property="Background" Value="LightBlue"></Setter>
                </Style.Triggers>
            </Style>
        </DataGridTextColumn.CellStyle>
    </DataGridTextColumn>
</DataGrid.Columns>

这里是我正在使用的多值转换器:

Here is the multi value converter I'm using:

/// <summary>
/// https://stackoverflow.com/questions/1224144/change-background-color-for-wpf-textbox-in-changed-state
/// 
/// Property changed and display it on a datagrid.
/// 
/// Boolean Converter
/// </summary>

public class BackgroundColorConverterBool : IMultiValueConverter
{
    /// <summary>
    /// 
    /// </summary>
    /// <param name="values"></param>
    /// <param name="targetType"></param>
    /// <param name="parameter"></param>
    /// <param name="culture"></param>
    /// <returns>True is property has changed</returns>
    public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture)
    {
        if (values[0] is null || values[1] is null) return false;


        if (values.Length == 2)
            if (values[0].Equals(values[1]))
                return false;
            else
                return true;
        else
            return true;
    }

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

更新

使用标记为我的答案的解决方案,我可以对其进行扩展以推广UpdateState()方法。

Using the solution marked as my answer I was able to expand on it to generalize the UpdateState() method.

foreach (var prop in this.GetType().GetProperties())
    _memo[prop.Name] = prop.GetValue(this);


推荐答案

我不会依赖OneTime绑定模式和技巧清除绑定以跟踪数据更改。

I wouldn't rely on OneTime binding mode and tricks with clearing binding to track changes in data. Implement something like Memento pattern instead.

添加以下代码,将代码存储在Item类中:

Add this code which stores state in Item class:

private Dictionary<string, object> _memo = new Dictionary<string, object>();
public object this[string key]
{
    get 
    {
        object o;
        _memo.TryGetValue(key, out o);
        return o;
    }
}

public void UpdateState()
{
    _memo["Name"] = Name;
    _memo["Description"] = Description;
    _memo["Alias"] = Alias;
    _memo["Value"] = Value;
    OnPropertyChanged("Item[]");
}

使索引器 this [] 工作,您必须重命名类(例如,重命名为 ItemVm ),因为类名和成员名不能相同,.NET使用 Item 作为索引器属性名称。

to make indexer this[] work you have to rename class (e.g. to ItemVm), because class name and member name can't be the same, and .NET uses "Item" as indexer property name.

请注意,索引器的通知具有 Item [] 格式和 VerifyProperty()方法也应固定:

note that notifications for indexer have "Item[]" format, and VerifyProperty() method should be fixed too:

private void VerifyProperty(string propertyName)
{
    if (propertyName == null || propertyName == "Item[]")
        return;

现在,要在窗口中使用未修改的值,请像这样绑定到索引器:

now, to use unmodified value in window, bind to indexer like this:

<Style TargetType="{x:Type DataGridCell}">
    <Style.Triggers>
        <DataTrigger Value="True">
            <DataTrigger.Binding>
                <MultiBinding Converter="{StaticResource BackgroundColorConverterBool}">
                    <Binding Path="Value"   />
                    <Binding Path="[Value]" />
                </MultiBinding>
            </DataTrigger.Binding>

            <Setter Property="Background" Value="LightBlue"/>
        </DataTrigger>
    </Style.Triggers>
</Style>

在创建项目时保存初始状态:

save initial state when creating items:

for(var i = 0; i < 100; i++)
{
    Items.Add(new ItemVm
    {
        Alias = string.Format("Item {0}", i.ToString()),
        Description = string.Format("Description {0}", i.ToString()),
        Name = string.Format("Name {0}", i.ToString()),
        Value = string.Format("Value {0}", i.ToString())
    });
    Items[i].UpdateState();
}

并在按钮单击时保存状态更改:

and save changes in state on button click:

private void Button_Click(object sender, RoutedEventArgs e)
{
    UIHelper.UpdateDataBindings<Control>(this);

    foreach(var item in Items)
    {
        item.UpdateState();
    }
}

这篇关于在DataGridCell上更新MultiBinding的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆