- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
我有一个类,它有两个 ObservableCollection
当我将它们绑定(bind)到图表时,一切都很完美,我得到了两个 LineSeries。如果我将其中一个绑定(bind)到 DataGrid,其中包含“日期”列和“值”列,则可以再次完美运行。我什至得到了我需要的 TwoWay 绑定(bind)。
但是,我需要一个包含“日期”列以及目标和实际值各一列的 DataGrid。问题是我需要列出某个范围内的所有日期,而其中一些日期可能在目标、实际值或两者中没有相应的值。
因此,我决定执行一个 MultiBinding,将目标和实际值作为输入,并输出组合的 TimeSeriesC,只要其中一个原始值没有值,就会输出空值。
它可以工作,但不会响应底层数据的任何更改。
这工作正常(绑定(bind)到一个 ObservableCollection):
<ctrls:DataGrid Grid.Row="1" Height="400" AutoGenerateColumns="False" CanUserDeleteRows="False" SelectionUnit="Cell">
<ctrls:DataGrid.ItemsSource>
<Binding Path="Targets"/>
<!--<MultiBinding Converter="{StaticResource TargetActualListConverter}">
<Binding Path="Targets"/>
<Binding Path="Actuals"/>
</MultiBinding>-->
</ctrls:DataGrid.ItemsSource>
<ctrls:DataGrid.Columns>
<ctrls:DataGridTextColumn Header="Date" Binding="{Binding Date,StringFormat={}{0:ddd, MMM d}}"/>
<ctrls:DataGridTextColumn Header="Target" Binding="{Binding Value}"/>
<!--<ctrls:DataGridTextColumn Header="Target" Binding="{Binding Value[0]}"/>
<ctrls:DataGridTextColumn Header="Actual" Binding="{Binding Value[1]}"/>-->
</ctrls:DataGrid.Columns>
这有效,但仅在首次初始化时有效。对更改通知没有响应:
<ctrls:DataGrid Grid.Row="1" Height="400" AutoGenerateColumns="False" CanUserDeleteRows="False" SelectionUnit="Cell">
<ctrls:DataGrid.ItemsSource>
<!--<Binding Path="Targets"/>-->
<MultiBinding Converter="{StaticResource TargetActualListConverter}">
<Binding Path="Targets"/>
<Binding Path="Actuals"/>
</MultiBinding>
</ctrls:DataGrid.ItemsSource>
<ctrls:DataGrid.Columns>
<ctrls:DataGridTextColumn Header="Date" Binding="{Binding Date,StringFormat={}{0:ddd, MMM d}}"/>
<!--<ctrls:DataGridTextColumn Header="Target" Binding="{Binding Value}"/>-->
<ctrls:DataGridTextColumn Header="Target" Binding="{Binding Value[0]}"/>
<ctrls:DataGridTextColumn Header="Actual" Binding="{Binding Value[1]}"/>
</ctrls:DataGrid.Columns>
这是我的 IMultiValueConverter:
class TargetActualListConverter : IMultiValueConverter
{
public object Convert(object[] values, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
TimeSeries<double> Targets = values[0] as TimeSeries<double>;
TimeSeries<double> Actuals = values[1] as TimeSeries<double>;
DateTime[] range = TimeSeries<double>.GetDateRange(Targets, Actuals);//Get min and max Dates
int count = (range[1] - range[0]).Days;//total number of days
DateTime currDate = new DateTime();
TimeSeries<double?[]> combined = new TimeSeries<double?[]>();
for (int i = 0; i < count; i++)
{
currDate = range[0].AddDays(i);
double?[] vals = { Targets.Dates.Contains(currDate) ? (double?)Targets.GetValueByDate(currDate) : null, Actuals.Dates.Contains(currDate) ? (double?)Actuals.GetValueByDate(currDate) : null };
combined.Add(new TimeValue<double?[]>(currDate, vals));
}
return combined;
}
public object[] ConvertBack(object value, Type[] targetTypes, object parameter, System.Globalization.CultureInfo culture)
{
TimeSeries<double?[]> combined = value as TimeSeries<double?[]>;
TimeSeries<double> Targets = new TimeSeries<double>();
TimeSeries<double> Actuals = new TimeSeries<double>();
foreach (TimeValue<double?[]> tv in combined)
{
if(tv.Value[0]!=null)
Targets.Add(new TimeValue<double>(tv.Date,(double)tv.Value[0]));
if (tv.Value[1] != null)
Actuals.Add(new TimeValue<double>(tv.Date, (double)tv.Value[1]));
}
TimeSeries<double>[] result = { Targets, Actuals };
return result;
}
}
我不能离得太远,因为它显示了值。
我做错了什么?或者,是否有更简单的方法来做到这一点?
谢谢大家!
最佳答案
看起来这是由转换器引起的。 ObservableCollection 实现 INotifyCollectionChanged,当集合发生更改(添加/删除/替换/移动/重置)时,它会通知 UI。这些都是对集合的更改,而不是集合的内容,因此您之前看到的更新是由于您的类实现了 INotifyPropertyChanged。由于 MultiCoverter 返回新对象的新集合,因此初始集合中的数据不会传播到这些集合,因为没有与原始对象的绑定(bind)可供它们通知。
我建议的第一件事是看一下 CompositeCollection元素并查看是否满足您的需求。
您可以使用以下内容维护原始对象,而不是按原样设置 ItemsSource:
<ctrls:DataGrid.ItemsSource>
<CompositeCollection>
<CollectionContainer Collection="{Binding Targets}" />
<CollectionContainer Collection="{Binding Actuals}" />
</CompositeCollection>
</ctrls:DataGrid.ItemsSource>
(我假设“不响应基础数据的任何更改”是指更改值,而不是修改集合,如果我不正确,请告诉我,我会更深入地研究它。 )
编辑添加内容
如果这不起作用,替代方法是编写一个新类来包装目标和实际集合。然后可以使用这些包装器创建单个 ObservableCollection。这实际上是比使用 ValueConverter 或使用 CompositeCollection 更好的方法。无论使用哪种方法,您都会失去一些最初存在的功能。通过使用值转换器重新创建集合,它不再直接绑定(bind)到原始对象,因此属性通知可能会丢失。通过使用 CompositeCollection,您不再拥有可以通过添加/删除/移动等进行迭代或修改的单个集合,因为它必须知道要操作哪个集合。
这种类型的包装功能在 WPF 中非常有用,并且是 ViewModel 的非常简化的版本,是 M-V-VM 设计模式的一部分。当您无权访问底层类来添加 INotifyPropertyChanged 或 IDataErrorInfo 时,可以使用它,并且还可以帮助向底层模型添加附加功能,例如状态和交互。
这是一个演示此功能的简短示例,其中我们的两个初始类都具有相同的 Name 属性,并且不实现它们之间不共享的 INotifyPropertyChanged。
public partial class Window1 : Window
{
public Window1()
{
InitializeComponent();
Foo foo1 = new Foo { ID = 1, Name = "Foo1" };
Foo foo3 = new Foo { ID = 3, Name = "Foo3" };
Foo foo5 = new Foo { ID = 5, Name = "Foo5" };
Bar bar1 = new Bar { ID = 1, Name = "Bar1" };
Bar bar2 = new Bar { ID = 2, Name = "Bar2" };
Bar bar4 = new Bar { ID = 4, Name = "Bar4" };
ObservableCollection<FooBarViewModel> fooBar = new ObservableCollection<FooBarViewModel>();
fooBar.Add(new FooBarViewModel(foo1, bar1));
fooBar.Add(new FooBarViewModel(bar2));
fooBar.Add(new FooBarViewModel(foo3));
fooBar.Add(new FooBarViewModel(bar4));
fooBar.Add(new FooBarViewModel(foo5));
this.DataContext = fooBar;
}
}
public class Foo
{
public int ID { get; set; }
public string Name { get; set; }
}
public class Bar
{
public int ID { get; set; }
public string Name { get; set; }
}
public class FooBarViewModel : INotifyPropertyChanged
{
public Foo WrappedFoo { get; private set; }
public Bar WrappedBar { get; private set; }
public int ID
{
get
{
if (WrappedFoo != null)
{ return WrappedFoo.ID; }
else if (WrappedBar != null)
{ return WrappedBar.ID; }
else
{ return -1; }
}
set
{
if (WrappedFoo != null)
{ WrappedFoo.ID = value; }
if (WrappedBar != null)
{ WrappedBar.ID = value; }
this.NotifyPropertyChanged("ID");
}
}
public string BarName
{
get
{
return WrappedBar.Name;
}
set
{
WrappedBar.Name = value;
this.NotifyPropertyChanged("BarName");
}
}
public string FooName
{
get
{
return WrappedFoo.Name;
}
set
{
WrappedFoo.Name = value;
this.NotifyPropertyChanged("FooName");
}
}
public FooBarViewModel(Foo foo)
: this(foo, null) { }
public FooBarViewModel(Bar bar)
: this(null, bar) { }
public FooBarViewModel(Foo foo, Bar bar)
{
WrappedFoo = foo;
WrappedBar = bar;
}
public event PropertyChangedEventHandler PropertyChanged;
private void NotifyPropertyChanged(String info)
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(info));
}
}
}
然后在窗口中:
<ListView ItemsSource="{Binding}">
<ListView.View>
<GridView>
<GridViewColumn Header="ID" DisplayMemberBinding="{Binding ID}"/>
<GridViewColumn Header="Foo Name" DisplayMemberBinding="{Binding FooName}"/>
<GridViewColumn Header="Bar Name" DisplayMemberBinding="{Binding BarName}"/>
</GridView>
</ListView.View>
</ListView>
关于WPF DataGrid - 将 TimeSeries 与 MultiBinding 相结合,丢失更改通知。为什么?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/875773/
MultiBinding 到背景属性不起作用。转换后,背景只是变成系统的默认颜色,而不是我在 MultiValueConverter 中设置的颜色。其他一切都已正确设置。我的 MultiBinding
让我们考虑一种动物 Model如下: public class Animal { public string name { set; get; } public int age { s
下面的代码将列宽:Samp1.ActualWidth 和 Samp2.ActualWidth 绑定(bind)到 StatName.Width。请参阅:Bind DataGrid Column Wid
我在尝试将现有 XAML 转换为 MultiBinding 时遇到问题。 当前代码(需要替换)是 我现在拥有的:
我正在尝试转换一些单位。Convertback 函数应如何处理以下内容。获得以下 XAML。标签设置为我的 ViewModel 中的唯一对象。 这种风格...
我想做类似的事情 post但使用MultipleBindings。 所以是这样的:
以下代码用于绑定(bind) ListView,但对 ListView 的任何更改都不会返回到内存中的数据结构。当我有标准绑定(bind)时,它可以双向工作,但不能使用多重绑定(bind)。我需要使用
在 中设置样式(假设转换器返回红色)
关闭。这个问题需要debugging details .它目前不接受答案。 想改进这个问题?将问题更新为 on-topic对于堆栈溢出。 1年前关闭。 Improve this question
我正在尝试使用标签控件在 XAML 中显示一个字符串。以下是我的 XAML 代码:
如何跳过更新MultiBinding的一些子绑定(bind)?我已经在代码隐藏中定义了一个 MultiBinding ,它需要两次读取-仅属性和一个普通属性生成单个值。在 ConvertBack 的情
我正在 wpf TreeView 上使用上下文菜单,并且我几乎可以满足我的需求。在解释问题之前,让我先解释一下上下文菜单的 XAML 定义的作用。 对于上下文菜单中的每个菜单项,我们都有一个命令,该命
使用 com.google.inject.multibindings.Multibinder 时,我对泛型有点困惑如下: interface MessageParser { fun accept(
我知道我可以使用特定注释进行 Guice 多重绑定(bind),如下所示 Multibinder.newSetBinder(binder(), Bound.class, Annotation.clas
基本上我需要知道的是如何发送 HierarchicalDataTemplate 的来源绑定(bind)到一个绑定(bind)中,这就是我所拥有的:
我创建了一个内联 MultiBinding使用 this post作为引用。更具体地说,我正在使用 Christian Myksvoll 的答案来创建自定义绑定(bind)。我的类(class)看起来
我有一个内置动态语言切换的应用程序。根据所选的文化,整个应用程序中的字符串都会发生变化。翻译后的字符串及其原始值来自资源文件。我使用绑定(bind)将资源值附加到按钮、标签等。大部分绑定(bind)发
我想做的很简单。我有一个窗口,我希望将标题绑定(bind)到两个不同的属性。每次属性之一更改时,标题都应更新。 我首先尝试的但没有成功 错
我创建了一个自定义的 MultiValue Converter 来在 MultiBinding 到 TextBox 时执行一些逻辑;但是我不想使用 convertBack,因为绑定(bind)值没有编
我这辈子都做不到。我需要从文本 block 中的一对时间跨度对象显示 hh:mm,但它无法正常工作。这是我目前所拥有的:
我是一名优秀的程序员,十分优秀!