获得新标签的母公司增加绑定的TabControl后(MVVM) [英] Getting parent of new tab after adding to bound TabControl (mvvm)

查看:588
本文介绍了获得新标签的母公司增加绑定的TabControl后(MVVM)的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述



我用下面的指南添加一个关闭按钮我的标签84213 /如何到添加-A-关闭按钮至A-WPF-TabItem的相对=nofollow> http://www.codeproject.com/Articles/84213/How-to-add-a-关闭按钮至A-WPF的TabItem的



由于该事件使用的附加标签的父删除,这已经成为一个问题从TabControl的标签。我结合使用MVVM标签控制,因此父属性显然没有被设置,给我当事件试图从中取出父一个空引用异常。



下面的的结合,你的想法:

 < TabControl的名称=TabControl的保证金=0,22 0.2,-5.2的ItemsSource ={绑定选项卡}后台=#FF4C76B2/> 



在这里被添加标签继承人。

 私人无效AddTab(对象TABNAME)
{
ClosableTab newTab =新ClosableTab();
newTab.Title =称号?
//newTab.Header = TABNAME;
文本框测试=新的TextBox();

test.Text =CONTENT(+ TABNAME +)GOES HERE;
newTab.Content =测试;

Tabs.Add(newTab);
OnPropertyChanged(标签);
}

下面就是空引用正在发生的事件:



 无效button_close_Click(对象发件人,RoutedEventArgs E)
{
((TabControl的)this.Parent).Items.Remove (这个);
}



在我看来有两个选择:




  • 尝试寻找另一种方式来删除该选项卡(无父
    属性)

  • 尝试找到一种方法以某种方式设置父属性(它不能是
    直接完成,它抛出一个编译器错误)


解决方案

这听起来并不像MVVM我。我们用的数据工作的,不是的 UI元素的。我们用的是包含所有满足一些要求,数据所需的属性类集合绑定工作在的DataTemplate 取值这些属性的UI控件。通过这种方式,我们通过添加数据项到这些集合添加UI控件,让美妙的WPF模板系统照顾的UI。



例如,你有一个的TabControl ,我们要添加或...以适当的方式MVVM删除 TabItem的秒。首先,我们需要一个可以代表项目集合每个 TabItem的

 公共静态的DependencyProperty ItemsProperty = DependencyProperty.Register(项目,typeof运算(的ObservableCollection<串GT;)的typeof(TestView)); 

公众的ObservableCollection<串GT;项目
{
{返回(的ObservableCollection<串GT;)的GetValue(ItemsProperty); }
集合{的SetValue(ItemsProperty,值); }
}



我只是用的DependencyProperty ,因为我在用户控件撞倒这件事,我只是用集合字符串取值为了简单。你需要创建一个包含类的所有的整个 TabItem的内容所需的数据。接下来,让我们来看看的TabControl

 <的TabControl的ItemsSource = {绑定表项}的ItemTemplate ={StaticResource的ItemTemplate中}/> 

我们的数据绑定收集到 TabControl.ItemsSource 财产和我们设定的 TabControl.ItemTemplate 资源名为的ItemTemplate 。现在,让我们看到:

 的xmlns:系统=CLR的命名空间:系统;装配= mscorlib程序
..
<的DataTemplate X:键=ItemTemplate中数据类型={X:类型系统:字符串}>
< TabItem的标题={结合}/>
< / DataTemplate中>

的DataTemplate 定义了每个项目我们收集的样子。为简单起见,我们的字符串是刚刚绑定到 TabItem.Header 属性数据。这意味着,我们加入到集合中的每个项目,我们现在将得到一个新的 TabItem的标题属性设置为字符串的值:

  Items.Add(标签1); 
Items.Add(表2);
Items.Add(标签3);

请注意,我包括系统 XML命名空间前缀的完整性,但你不需要因为你的数据类型将自己的自定义类。你需要更多的的DataTemplate 太。例如,如果您的自定义类有一个标题属性和内容属性,这是另一个自定义类,让我们说名为内容,包含所有的 TabItem.Content 财产的属性,你可以这样做:

 <的DataTemplate X:键=ItemTemplate中数据类型={X:类型YourPrefix:YourClass}> 
< TabItem的标题={结合头}CONTENT ={结合内容}/>
< / DataTemplate中>
<数据类型的DataTemplate ={X:类型YourPrefix:内容}>
< YourPrefix:SomeUserControl的DataContext ={结合}/>
< / DataTemplate中>



所以,这将给你 TabItem的 s的标题 S设定和内容来自 SomeUserControl 您可以设计。你并不需要使用用户控件 S,你可以只添加更多的UI控件为的DataTemplate 。但是,你需要的地方增加更多的控制......多类和属性,始终记住要正确实现基本的 INotifyPropertyChanged的接口。



最后,回答在适当的方式MVVM你的问题...删除 TabItem的,您只需删除涉及 TabItem的从集合。简单...或者它本来如果你真的喜欢过你宣称使用MVVM了。这真是值得我们学习MVVM正确,你将很快看到收益。我将离开你找到自己的教程,因为有许多可供选择。






更新>>>



您事件处理还不是那么MVVM ......你不需要在任何地方通过任何视图模型的参考。在MVVM方式是在视图模型可以使用的命令。特别是,您应该调查 RelayCommand 。我有我自己的版本,但这些命令使我们能够从绑定的数据执行操作按钮和使用方法或内联其他UI控件将委托■在视图模型(其中行动和 canExecute CommandParameter 值):

 <按钮内容=关闭标签命令={结合CloseTabCommand}
CommandParameter ={结合}/>

...

公众的ICommand CloseTabCommand
{
{返回新ActionCommand(动作= GT; Items.Remove(动作),
canExecute => canExecute = NULL&放大器;!&安培; Items.Contains(canExecute)); }
}



所以,无论视图模式有你的标签集合应该有一个 AddTabCommand CloseTabCommand 添加和从<$ C $删除项目C>标签集合。但是,仅仅是明确的,因为这能正常工作,你的 ClosableTab 类应该是一个数据类,而不是一个UI控件类。使用的DataTemplate 来指定它,如果它是一个UI控件。



您可以找到关于 RelayCommand >在MSDN上。


I'm adding a close button to my tabs using the following guide:

http://www.codeproject.com/Articles/84213/How-to-add-a-Close-button-to-a-WPF-TabItem

This has become a problem because the event uses the 'parent' of the added tab to remove that tab from the tabcontrol. I'm binding the tab control using mvvm, so the parent property is apparently not being set and giving me a null reference exception for the parent when the event tries to remove from it.

Here's the binding so you get the idea:

<TabControl Name="tabControl" Margin="0,22,0.2,-5.2" ItemsSource="{Binding Tabs}" Background="#FF4C76B2"/>

Heres where the tabs are being added.

private void AddTab(object tabName)
{
    ClosableTab newTab = new ClosableTab();
    newTab.Title = "title?";
    //newTab.Header = tabName;
    TextBox test = new TextBox();

    test.Text = "CONTENT (" + tabName + ") GOES HERE";
    newTab.Content = test;

    Tabs.Add(newTab);
    OnPropertyChanged("Tabs");
}

Here is the event where the null reference is taking place:

void button_close_Click(object sender, RoutedEventArgs e)
{
    ((TabControl)this.Parent).Items.Remove(this);
}

As I see it there are two options:

  • try to find another way to remove the tab (without the parent property)
  • try to find a way to somehow set the parent property (which cant be done directly, it throws a compiler error)

解决方案

That doesn't sound like MVVM to me. We work with data, not UI elements. We work with collections of classes that contain all of the properties required to fulfil some requirement and data bind those properties to the UI controls in DataTemplates. In this way, we add UI controls by adding data items into these collections and let the wonderful WPF templating system take care of the UI.

For example, you have a TabControl that we want to add or remove TabItems from... in a proper MVVM way. First, we need a collection of items that can represent each TabItem:

public static DependencyProperty ItemsProperty = DependencyProperty.Register("Items", typeof(ObservableCollection<string>), typeof(TestView));

public ObservableCollection<string> Items
{
    get { return (ObservableCollection<string>)GetValue(ItemsProperty); }
    set { SetValue(ItemsProperty, value); }
}

I'm just using a DependencyProperty because I knocked this up in a UserControl and I'm just using a collection of strings for simplicity. You'll need to create a class that contains all of the data required for the whole TabItem content. Next, let's see the TabControl:

<TabControl ItemsSource="{Binding Items}" ItemTemplate="{StaticResource ItemTemplate}" />

We data bind the collection to the TabControl.ItemsSource property and we set the TabControl.ItemTemplate to a Resource named ItemTemplate. Let's see that now:

xmlns:System="clr-namespace:System;assembly=mscorlib"
...
<DataTemplate x:Key="ItemTemplate" DataType="{x:Type System:String}">
    <TabItem Header="{Binding}" />
</DataTemplate>

This DataTemplate defines what each item in our collection will look like. For simplicity's sake, our strings are just data bound to the TabItem.Header property. This means that for each item we add into the collection, we'll now get a new TabItem with its Header property set to the value of the string:

Items.Add("Tab 1");
Items.Add("Tab 2");
Items.Add("Tab 3");

Note that I included the System XML Namespace Prefix for completeness, but you won't need that because your DataType will be your own custom class. You'll need more DataTemplates too. For example, if your custom class had a Header property and a Content property, which was another custom class, let's say called Content, that contained all of the properties for the TabItem.Content property, you could do this:

<DataTemplate x:Key="ItemTemplate" DataType="{x:Type YourPrefix:YourClass}">
    <TabItem Header="{Binding Header}" Content="{Binding Content}" />
</DataTemplate> 
<DataTemplate DataType="{x:Type YourPrefix:Content}">
    <YourPrefix:SomeUserControl DataContext="{Binding}" />
</DataTemplate>

So this would give you TabItems with Headers set and Content that comes from SomeUserControl which you could design. You don't need to use UserControls, you could just add more UI controls to either DataTemplate. But you will need to add more controls somewhere... and more classes and properties, always remembering to correctly implement the essential INotifyPropertyChanged interface.

And finally, to answer your question in the proper MVVM way... to remove a TabItem, you simply remove the item that relates to that TabItem from the collection. Simple... or it would have been if you really had been using MVVM like you claim. It's really worth learning MVVM properly as you'll soon see the benefits. I'll leave you to find your own tutorials as there are many to chose from.


UPDATE >>>

Your event handling is still not so MVVM... you don't need to pass a reference of any view model anywhere. The MVVM way is to use commands in the view model. In particular, you should investigate the RelayCommand. I have my own version, but these commands enable us to perform actions from data bound Buttons and other UI controls using methods or inline delegates in the view model (where action and canExecute in this example are the CommandParameter values):

<Button Content="Close Tab" Command="{Binding CloseTabCommand}" 
    CommandParameter="{Binding}" />

...

public ICommand CloseTabCommand
{
    get { return new ActionCommand(action => Items.Remove(action), 
        canExecute => canExecute != null && Items.Contains(canExecute)); }
}

So whatever view model has your Tabs collection should have an AddTabCommand and a CloseTabCommand that add and remove items from the Tabs collection. But just to be clear, for this to work properly, your ClosableTab class should be a data class and not a UI control class. Use a DataTemplate to specify it if it is a UI control.

You can find out about the RelayCommand from this article on MSDN.

这篇关于获得新标签的母公司增加绑定的TabControl后(MVVM)的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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