我正在使用MVVMLight。这就是我从示例here获得的内容。
#include "GameManager.h"
#include "Input.h"
#include "Player"
#include <iostream>
#include <string>
using namespace std;
const int maxPlayerCnt = 10;
static Player p1, p2, morePlayers[maxPlayerCnt];
int main()
{
GameManager game;
game.Game(p1, p2, morePlayers);
return 0;
}
问题是绑定属性InlineList永远不会更新。我没有看到我添加到集合ObservableCollection的任何文本。当我在OnPropertyChanged方法中放置一个断点时,它永远不会被击中。我知道我的数据上下文设置正确,因为其他绑定控件工作。 可能是什么问题?
答案 0 :(得分:-1)
好的,你只需要在你的BindableTextBlock中添加这些原始解决方案。我们在这里做的是我们为收集更改时添加处理程序(意味着添加新值),我们只做那个设置集合时。因此,对于您在xaml中的绑定,您在VM fires集合中对集合所做的每个更改都会在textblock中更改事件,而后者只是将值附加到内联。
private void CollectionChangedHandler(object sender, NotifyCollectionChangedEventArgs e)
{
Inlines.AddRange(e.NewItems);
}
private static void OnPropertyChanged(DependencyObject sender, DependencyPropertyChangedEventArgs e)
{
if (e.NewValue == null) return;
var textBlock = (BindableTextBlock)sender;
textBlock.InlineList.CollectionChanged += textBlock.CollectionChangedHandler;
}
好的,我看到了发生了什么,所以首先解释一个例子。
首先介绍一些关于wpf的基本概念:
为了让您的视图通知ViewModel中的绑定变量(或者此时的任何DataContext),您必须使用已更改属性的名称进行RaisePropertyChanged事件或使用“#”;以某种方式这样做:) - 像ObservableCollection。
所以有些用例:
您有一个带字段的属性 - &gt;通常的做法就是这样:
private ICollection<Inline> _inlineList;
public ICollection<Inline> InlineList
{
get
{
return _inlineList;
}
set
{
_inlineList = value;
RaisePropertyChanged("InlineList");
}
}
这可确保在为InlineList设置新值时,将通知视图
或者就你的情况而言:
private ICollection<Inline> _inlineList;
public ICollection<Inline> InlineList
{
get { return _inlineList; }
set { Set(() => InlineList, ref _inlineList, value); }
}
如果你查看Set方法的描述,你会发现它正在设置值并提升属性(还有一些东西)
您希望自动更新并使用 ObservableCollection - &gt;我这样用它:
private ObservableCollection<ClientFilter> clientFilters;
public IEnumerable<ClientFilter> ClientFilters
{
get
{
if (this.clientFilters == null)
{
this.clientFilters = new ObservableCollection<ClientFilter>();
}
return this.clientFilters;
}
set
{
if (this.clientFilters == null)
{
this.clientFilters = new ObservableCollection<ClientFilter>();
}
SetObservableValues<ClientFilter>(this.clientFilters, value);
}
}
方法SetObservableValues位于我的主ViewModel中,并且正在执行此操作:
public static void SetObservableValues<T>(
ObservableCollection<T> observableCollection,
IEnumerable<T> values)
{
if (observableCollection != values)
{
observableCollection.Clear();
foreach (var item in values)
{
observableCollection.Add(item);
}
}
}
此方法确保如果对obs集合的引用不相同,它将清除旧的并重用它,因为绑定时绑定到引用的常见错误是然后更改引用本身而不是值,反过来不会更新UI上的任何内容,你认为绑定被破坏了:)
因此,如果您希望它正常运行,您只需添加/删除Collection / Enumerable ClientFilters
因此,我不能100%确定您想要达到的目标,但是您可以采取哪些措施来实现绑定工作
您的ViewModel
using GalaSoft.MvvmLight;
using GalaSoft.MvvmLight.Command;
using System.Collections.Generic;
using System.Windows;
using System.Windows.Documents;
namespace WpfApplication3.ViewModel
{
public class MainViewModel : ViewModelBase
{
public MainViewModel()
{
}
private ICollection<Inline> _inlineList;
public ICollection<Inline> InlineList
{
get { return _inlineList; }
set { Set(() => InlineList, ref _inlineList, value); }
}
public RelayCommand SendClicked
{
get
{
return new RelayCommand(() =>
{
InlineList = new List<Inline>
{
new Run("This is some bold text") { FontWeight = FontWeights.Bold },
new Run("Some more text"),
new Run("This is some text") { TextDecorations = TextDecorations.Underline }
};
});
}
}
}
}
您的自定义控件 - &gt; BindableTextBlock
using System.Collections.Generic;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
namespace WpfApplication3
{
public class BindableTextBlock : TextBlock
{
public ICollection<Inline> InlineList
{
get { return (ICollection<Inline>)GetValue(InlineListProperty); }
set { SetValue(InlineListProperty, value); }
}
public static readonly DependencyProperty InlineListProperty =
DependencyProperty.Register("InlineList", typeof(List<Inline>), typeof(BindableTextBlock), new UIPropertyMetadata(null, OnPropertyChanged));
private static void OnPropertyChanged(DependencyObject sender, DependencyPropertyChangedEventArgs e)
{
if (e.NewValue == null) return;
var textBlock = (BindableTextBlock)sender;
textBlock.Inlines.AddRange((ICollection<Inline>)e.NewValue);
}
}
}
你的XAML
在您的页面或窗口上(取决于平台)
DataContext="{Binding Main, Source={StaticResource Locator}}"
然后在里面
<StackPanel>
<Button Command="{Binding SendClicked}">SendClicked</Button>
<local:BindableTextBlock Background="Black" Foreground="AliceBlue"
Width = "Auto" Height="Auto"
InlineList="{Binding InlineList}"
>
</local:BindableTextBlock>
</StackPanel>
所有假设你有来自MVVM Light的ViewModelLocator注册你的视图模型
使用GalaSoft.MvvmLight.Ioc; 使用Microsoft.Practices.ServiceLocation;
namespace WpfApplication3.ViewModel
{
public class ViewModelLocator
{
public ViewModelLocator()
{
ServiceLocator.SetLocatorProvider(() => SimpleIoc.Default);
SimpleIoc.Default.Register<MainViewModel>();
}
public MainViewModel Main
{
get
{
return ServiceLocator.Current.GetInstance<MainViewModel>();
}
}
public static void Cleanup()
{
}
}
}
<强> ALTERNATIVE 强>
或者你也可以这样命令:
public RelayCommand SendClicked
{
get
{
return new RelayCommand(() =>
{
_inlineList = new List<Inline>();
InlineList.Add(new Run("This is some bold text") { FontWeight = FontWeights.Bold });
InlineList.Add(new Run("Some more text"));
InlineList.Add(new Run("This is some text") { TextDecorations = TextDecorations.Underline });
RaisePropertyChanged("InlineList");
});
}
}
但你必须使用另一种定义属性的选项,如我文章开头所述。
当然,您可以通过其他方式进行此操作。
再提一个建议 - &gt;在视图模型中使用UI元素被认为是不好的做法而不是MVVM的精神,所以在这个代码IMO中强烈建议改变体系结构。
帖子太长了(像往常一样),如果你需要附加说明,请告诉我。 干杯和快乐的编码;)