wpf Caliburn Micro、绑定和通知
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/13011406/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Caliburn Micro, Binding and Notifying
提问by EluciusFTW
After a couple of months of hands-on WPF I decided to give Caliburn Micro a shot. I have several things I can't get to work. I'll post the code first, see my questions/problems below:
经过几个月的 WPF 实践,我决定试一试 Caliburn Micro。我有几件事无法上班。我将首先发布代码,请参阅下面的问题/问题:
public class MainViewModel : PropertyChangedBase
{
BindableCollection<PlayerProfile> _playerProfiles = staticInfos.Load();
public BindableCollection<PlayerProfile> PlayerProfiles {
get { return _playerProfiles; }
set {
_playerProfiles = value;
NotifyOfPropertyChange(() => PlayerList);
}
}
string _tb_AddPlayer;
public string TB_AddPlayer {
get { return _tb_AddPlayer; }
set {
_tb_AddPlayer = value;
NotifyOfPropertyChange(() => TB_AddPlayer);
NotifyOfPropertyChange(() => CanAddPlayer);
}
}
List<string> _pl = new List<string>();
public List<string> PlayerList {
get{
foreach (PlayerProfile p in PlayerProfiles) {
if (!_pl.Contains(p.Name)) _pl.Add(p.Name);
}
return _pl;
}
set {
_pl = value;
NotifyOfPropertyChange(()=>PlayerList);
}
}
// Dummy Test String
string _test;
public string Test {
get { return _test; }
set {
_test = value;
NotifyOfPropertyChange(() => Test);
}
}
// Button Action
public void AddPlayer() {
_playerProfiles.Add(new PlayerProfile(TB_AddPlayer));
Test = "Pressed";
NotifyOfPropertyChange(() => PlayerProfiles);
}
public bool CanAddPlayer {
get { return true; }
// doesnt work: get { return !string.IsNullOrWhiteSpace(TB_AddPlayer); }
}
}
So here goes: I use the binding convention, i.e., a Property in the MainView should bind to the Element of same Name in the View.
所以这里是:我使用绑定约定,即 MainView 中的 Property 应该绑定到 View 中的同名元素。
First of all, notice that
PlayerListis just a list of the names of the Players inPlayerProfiles, which I created because when binding to aCombobox, they don't show up when I name theCombobox PlayerProfiles, yet they do when I go via the list and name itPlayerList- although I have overridden theToStringmethod in thePlayerProfile class. Why? This seems clumsy... (ThestaticInfos.Load()method populates thePlayerProfileswith several dummy names, if you are wondering...)When I type something in the Textbox (called
TB_AddPlayer) and press the button (calledAddPlayer) the Test string appears, so I know the action took place, but the new name does not appear in the comboboxAlso, If I use the commented line in the
CanAddPlayerProperty, the button never is enabled, not if I start typing, nor when the textbox looses focus with text in it. Why?
首先,请注意这
PlayerList只是PlayerProfiles我创建的球员姓名列表,因为当绑定到 a 时Combobox,当我命名时他们不会出现Combobox PlayerProfiles,但是当我通过列表并命名时他们会出现PlayerList- 虽然我已经覆盖ToString了PlayerProfile class. 为什么?这看起来很笨拙......(该staticInfos.Load()方法填充了PlayerProfiles几个虚拟名称,如果你想知道......)当我在文本框中键入内容(称为
TB_AddPlayer)并按下按钮(称为AddPlayer)时,会出现测试字符串,因此我知道操作已发生,但新名称未出现在组合框中此外,如果我在
CanAddPlayer属性中使用注释行,则按钮永远不会启用,如果我开始输入,也不会在文本框失去焦点时启用其中的文本。为什么?
Sorry for these basic questions, I have stared at the 'Hello World' caliburn example for hours and don't see what I am missing... Thx. in advance!
抱歉,对于这些基本问题,我已经盯着“Hello World”caliburn 示例看了好几个小时,但没有看到我遗漏了什么......谢谢。提前!
Edit: Here's the .xaml
编辑:这是 .xaml
<UserControl x:Class="MixGameM8_MVVM.Views.MainView"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:MixGameM8_MVVM.Views">
<UserControl.Resources>
<Style TargetType="TextBlock" x:Key="TB_A">
<Setter Property="Margin" Value="5,5,5,5" />
<Setter Property="HorizontalAlignment" Value="Center" />
<Setter Property="FontSize" Value="15" />
</Style>
<!-- ... Some more of this kind -->
</UserControl.Resources>
<Grid>
<!-- ... Grid definitions -->
<Border Style="{StaticResource Border_A}" Grid.Row="0" Grid.Column="0">
<StackPanel Name="SP_Controls">
<TextBlock Style="{StaticResource TB_A}" Text="Controls"/>
<ComboBox Style="{StaticResource CB_A}" Name="PlayerProfiles"/>
<StackPanel Orientation="Horizontal">
<TextBox Style="{StaticResource TBox_A}" Name="TB_AddPlayer" MinWidth ="100" />
<Button Style="{StaticResource Button_AddPlayer}" Content="Add Player" Name="AddPlayer" />
</StackPanel>
</StackPanel>
</Border>
<!-- ... And some more cells in the grid, one containing the dummy textbox -->
</Grid>
</UserControl>
采纳答案by devdigital
Firstly, I would start by removing your PlayerListproperty, and update your PlayerProfilesproperty like so:
首先,我将首先删除您的PlayerList财产,然后PlayerProfiles像这样更新您的财产:
public BindableCollection<PlayerProfile> PlayerProfiles {
get { return _playerProfiles; }
set {
_playerProfiles = value;
NotifyOfPropertyChange(() => PlayerProfiles);
}
}
Next, I would not call your view model properties something which describes how they are rendered, i.e. change TB_AddPlayerto just AddPlayer(or better still something like PlayerNameas that's what it is).
接下来,我不会将您的视图模型属性称为描述它们如何呈现的东西,即更改TB_AddPlayer为 just AddPlayer(或者更好PlayerName的是,它仍然是这样的)。
Next, if you call your ComboBox PlayerProfiles, then the binding should automatically happen via convention. In your AddPlayer method, you want to add the new player profile via your property, not the backing field:
接下来,如果您调用 ComboBox PlayerProfiles,则绑定应通过约定自动发生。在您的 AddPlayer 方法中,您希望通过您的属性而不是支持字段添加新的玩家配置文件:
Change:
改变:
public void AddPlayer() {
_playerProfiles.Add(new PlayerProfile(TB_AddPlayer));
Test = "Pressed";
NotifyOfPropertyChange(() => PlayerProfiles);
}
to:
到:
public void AddPlayer() {
this.PlayerProfiles.Add(new PlayerProfile(this.PlayerName));
}
Because PlayerProfiles is a BindableCollection, change notifications will be performed, and your ComboBox will be updated.
因为 PlayerProfiles 是一个 BindableCollection,将执行更改通知,并且您的 ComboBox 将被更新。
Also, I would always explicitly specify the access modifier for your backing fields, i.e. private string _playerName;not just string _playerName;
此外,我总是会为您的支持字段明确指定访问修饰符,即private string _playerName;不仅仅是字符串_playerName;
Try these changes, and update your code in the question if you still have problems.
尝试这些更改,如果仍有问题,请更新问题中的代码。
回答by Chen Kinnrot
I think I got the answers
我想我得到了答案
On your text box use updatesourcetrigger=property changed The Can Execute is not updating cause you didn't use the depends on (or dependencies dont remeber the name) attribute.
在您的文本框中使用 updatesourcetrigger=property changed The Can Execute is not updated 因为您没有使用依赖(或依赖项不记得名称)属性。
The combobox not updating cause you should bind it to a bindable collection.
组合框未更新导致您应该将其绑定到可绑定集合。

