积极答复者
如何获取绑定真实的根级绑定源?MVVM

问题
-
在View里
[Import] MaterialCategorysViewModel ViewModel { set { this.DataContext = value; } }
在view里我有一个Tab控件:
<TabControl Grid.Row="1" Name="tabControl1" SelectedIndex="{Binding SelectedTabIndex}"> <TabItem Header="概览" > <!--local:MaterialCategoryListView DataContext="{Binding}"/--> <TreeView Name="CategoryTreeView" ItemsSource="{Binding Path=Model}" ItemTemplate ="{StaticResource NavigationTemplate }" > <TreeView.ItemContainerStyle> <!-- This Style binds a TreeViewItem to a PersonViewModel. --> <Style TargetType="{x:Type TreeViewItem}"> <Setter Property="IsExpanded" Value="{Binding IsExpanded, Mode=TwoWay}" /> <Setter Property="IsSelected" Value="{Binding IsSelected, Mode=TwoWay,UpdateSourceTrigger=PropertyChanged}" /> <Setter Property="FontWeight" Value="Normal" /> <Style.Triggers> <Trigger Property="IsSelected" Value="True"> <Setter Property="FontWeight" Value="Bold" /> </Trigger> </Style.Triggers> </Style> </TreeView.ItemContainerStyle> </TreeView> </TabItem> <TabItem Header="基本" Name="tabItem1" DataContext="{Binding ElementName=CategoryTreeView, Path=SelectedItem}"> <Grid > <Grid.RowDefinitions> <RowDefinition Height="Auto" /> <RowDefinition Height="Auto" /> <RowDefinition Height="Auto" /> <RowDefinition Height="45*" /> <RowDefinition Height="387*" /> </Grid.RowDefinitions> <Grid.ColumnDefinitions> <ColumnDefinition Width="52" /> <ColumnDefinition Width="265" /> <ColumnDefinition Width="117" /> <ColumnDefinition Width="Auto" /> <ColumnDefinition Width="51" /> <ColumnDefinition Width="115*" /> </Grid.ColumnDefinitions> <Label Content="名称:" Height="28" HorizontalAlignment="Left" Margin="12,6,0,0" Name="label1" VerticalAlignment="Top" /> <Label Content="描述:" Grid.Row="1" Height="28" HorizontalAlignment="Left" Margin="12,5,0,0" Name="label2" VerticalAlignment="Top" /> <TextBox Grid.Column="1" Name="textBoxName" Height="23" HorizontalAlignment="Left" Margin="9,8,0,0" VerticalAlignment="Top" Width="250" Text="{jas:FocusBinding Path=Name, ValidatesOnDataErrors=True}" > <i:Interaction.Behaviors> <behaviors:FocusBehavior></behaviors:FocusBehavior> </i:Interaction.Behaviors> </TextBox> <TextBox Grid.Column="1" Grid.Row="1" Height="23" HorizontalAlignment="Left" Margin="9,7,0,0" Name="textBox2" VerticalAlignment="Top" Width="365" Grid.ColumnSpan="2" Text="{Binding Path=Description}"/> <csla:PropertyStatus Grid.Column="2" Margin="11,11,86,3" Name="propertyStatus1" Width="20" Height="20" Property="{Binding Path=Name }" /> <csla:PropertyStatus Grid.Column="4" Grid.Row="1" Margin="12,7,19,7" Name="propertyStatus2" Width="20" Height="20" Property="{Binding Path=Description}" /> </Grid> </TabItem> </TabControl>
如何从 text控件 textBoxName可以获取绑定的 this.DataContext = value;既ViewModel?
答案
-
Ok, 看来你使用了MEF,而且你里面还有一个 custom markup extension {jas:FocusBinding }. 当然对于这个markup extension 我肯定不是很了解,如果你觉得这个问题和这个相关的话,最好是提供下这些的具体信息。
不过你的问题是如何 当前 View 的 DataContext. 如果与MEF和上述markup extension无关的话,简单的做法就是:假如说你的View是一个 UserControl 类型的,你就可以用RelativeSource去找到这个View实例,然后设置这个TextBox的DataContext.
<TextBox Grid.Column="1" Name="textBoxName" Height="23" HorizontalAlignment="Left" Margin="9,8,0,0" VerticalAlignment="Top" Width="250" Text="{jas:FocusBinding Path=Name, ValidatesOnDataErrors=True}" DataContext="{Binding RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type UserCotnrol}}, Path=DataContext}"> <i:Interaction.Behaviors> <behaviors:FocusBehavior></behaviors:FocusBehavior> </i:Interaction.Behaviors> </TextBox>
Sincerely,
Bob Bao [MSFT]
MSDN Community Support | Feedback to us
Get or Request Code Sample from Microsoft
Please remember to mark the replies as answers if they help and unmark them if they provide no help.
- 已标记为答案 Cuiqs 2011年9月8日 15:43
全部回复
-
别急,论坛上是不是实时都能回复的。我们需要点时间来看下,不过今天肯定我会给你一个回复的。
Bob Bao [MSFT]
MSDN Community Support | Feedback to us
Get or Request Code Sample from Microsoft
Please remember to mark the replies as answers if they help and unmark them if they provide no help.
-
Ok, 看来你使用了MEF,而且你里面还有一个 custom markup extension {jas:FocusBinding }. 当然对于这个markup extension 我肯定不是很了解,如果你觉得这个问题和这个相关的话,最好是提供下这些的具体信息。
不过你的问题是如何 当前 View 的 DataContext. 如果与MEF和上述markup extension无关的话,简单的做法就是:假如说你的View是一个 UserControl 类型的,你就可以用RelativeSource去找到这个View实例,然后设置这个TextBox的DataContext.
<TextBox Grid.Column="1" Name="textBoxName" Height="23" HorizontalAlignment="Left" Margin="9,8,0,0" VerticalAlignment="Top" Width="250" Text="{jas:FocusBinding Path=Name, ValidatesOnDataErrors=True}" DataContext="{Binding RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type UserCotnrol}}, Path=DataContext}"> <i:Interaction.Behaviors> <behaviors:FocusBehavior></behaviors:FocusBehavior> </i:Interaction.Behaviors> </TextBox>
Sincerely,
Bob Bao [MSFT]
MSDN Community Support | Feedback to us
Get or Request Code Sample from Microsoft
Please remember to mark the replies as answers if they help and unmark them if they provide no help.
- 已标记为答案 Cuiqs 2011年9月8日 15:43
-
谢谢,Bobo
{jas:FocusBinding } 在这里是个关键。 我需要在ViewModel控制View里的控件的Focus. Jas:FocusBinding可以参考http://joshsmithonwpf.wordpress.com/2010/03/16/control-input-focus-from-viewmodel-objects/
现在的问题是这样的。我在ViewModel里继承了这个扩展的IFocusMover接口:
public class MaterialCategorysViewModel:ViewModel<MaterialCategorys>,IFocusMover
在View里,我用TreeView来绑定MaterialCategorys. 然后用下面的表达式来绑定Treeview里的选定的行"{Binding ElementName=CategoryTreeView, Path=SelectedItem}"> 。
然后再绑定到这个行里的列,如Text="{jas:FocusBinding Path=Name, ValidatesOnDataErrors=True}".
Focusbinding这个扩展:
public class FocusBinding : BindingDecoratorBase { public override object ProvideValue(IServiceProvider provider) { DependencyObject elem; DependencyProperty prop; if (base.TryGetTargetItems(provider, out elem, out prop)) { FocusController.SetFocusableProperty(elem, prop); } return base.ProvideValue(provider); } }
这个扩展会获取textName以及我绑定的属性Text。 在这个扩展里,他通过:element.GetValue(FrameworkElement.DataContextProperty)获取这个控件的DataContextProperty. 如果对于这个控件是直接绑定到Usercontrol的Datacontext的,就相当于直接绑定到了ViewModel。但是对于我的情况不一样,我的TextBox是绑定到TreeView的SelectedItem。 TreeView是绑定到Model。 Model是属于ViewModel
里的一个属性: public static readonly DependencyProperty ModelProperty;
儿现在用到这个:element.GetValue(FrameworkElement.DataContextProperty)。获取的只是一个Collection。而不是ViewModel. 所以我的问题是如何才能获取真实的绑定源头啊?
MaterialCategorysViewModel=>Model=>SelectedItem=>Name。 就是从Name怎么能够获取MaterialCategorysViewModel(ViewModel)这个绑定?
static void CreateHandler(DependencyObject elemnt, DependencyProperty property) { var focusMover = element.GetValue(FrameworkElement.DataContextProperty) as IFocusMover; if (focusMover == null) { var handler = element.GetValue(MoveFocusSinkProperty) as MoveFocusSink; if (handler != null) { handler.ReleaseReferences(); element.ClearValue(MoveFocusSinkProperty); } } else { var handler = new MoveFocusSink(element as UIElement, property); focusMover.MoveFocus += handler.HandleMoveFocus; element.SetValue(MoveFocusSinkProperty, handler); } }
-
额,看了你的描述,我觉得我的那个代码是可以解决你的问题的,通过RelativeSource把跟元素的DataContext引导到当前TextBox里来。你试一下。
Bob Bao [MSFT]
MSDN Community Support | Feedback to us
Get or Request Code Sample from Microsoft
Please remember to mark the replies as answers if they help and unmark them if they provide no help.
-
我没有用到Datacontext.
[Import] MaterialCategorysViewModel ViewModel { set { var src = (System.Windows.Data.CollectionViewSource)(this.FindResource("MaterialCategorysViewModelSource")); src.Source = new List<object> { value }; } }
在父窗体用到的是:<ad:DockableContent.Resources > <CollectionViewSource x:Key="MaterialCategorysViewModelSource"/> </ad:DockableContent.Resources>
我如何访问这个CollectionViewSource ? -
那你就可以用 StaticResoruce 来设置 TextBox的DataContext了:
<TextBox DataContext="{Binding Source={StaticResource MaterialCategorysViewModelSource}}" .../>
Bob Bao [MSFT]
MSDN Community Support | Feedback to us
Get or Request Code Sample from Microsoft
Please remember to mark the replies as answers if they help and unmark them if they provide no help.