wpf 用WPF C#中的多个控件组合创建自定义控件
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/38842082/
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
Create a Custom Control with the combination of multiple controls in WPF C#
提问by B.Balamanigandan
I wish to create a Custom Control, it should be a combination of predefined controls like Textbox, Button, ListBox, etc.,
我想创建一个自定义控件,它应该是文本框、按钮、列表框等预定义控件的组合,
Kindly refer the following Controls (Just a Sample)
请参考以下控件(只是一个示例)
<Grid.RowDefinitions>
<RowDefinition Height="30" />
<RowDefinition Height="50" />
</Grid.RowDefinitions>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="300" />
<ColumnDefinition Width="100" />
</Grid.ColumnDefinitions>
<TextBox Grid.Column="0" />
<Button Grid.Column="1" Content="Add" Margin="20,0" />
</Grid>
<ListBox ItemsSource="{Binding textBox}" Grid.Row="1" Margin="0,25">
<ListBoxItem />
</ListBox>
</Grid>
I need a combination of controls in a single custom control. I need to add the Textbox values in a ListItem while I'm hitting the button and finally I need the List from this control.
我需要单个自定义控件中的控件组合。当我点击按钮时,我需要在 ListItem 中添加文本框值,最后我需要这个控件中的列表。
Expected Custom Control (Just a Sample)
预期的自定义控件(只是一个示例)
<cust:MultiControl ItemsSource="{Binding stringCollection}" />
Description:
I need to get the list of string from the user. I added a TextBox to get the input from the User. I added a Button to add the text in a List<string>. To display the List I added a ListBox.
描述:我需要从用户那里获取字符串列表。我添加了一个 TextBox 来获取用户的输入。我添加了一个 Button 以在List<string>. 为了显示列表,我添加了一个列表框。
I need a Single control, it should inherit these three controls. In that I need an ItemsSourcefor two way binding. If the List<string>is updated, it should update the ItemSource.
我需要一个 Single 控件,它应该继承这三个控件。因为我需要一个ItemsSourcefor two way binding。如果List<string>更新了,它应该更新 ItemSource。
I'm using this structure in more than 15 places. So, I wish to make it as Custom control. Kindly assist me how to implement this as a single control ?
我在超过 15 个地方使用了这种结构。因此,我希望将其设为自定义控件。请帮助我如何将其实现为单个控件?
I don't need a User Control, I need a Custom Control kindly assist me...
我不需要用户控件,我需要一个自定义控件,请帮助我...
Item Source ViewModel Collection is not updating even-though the ItemsSource has value.
即使 ItemsSource 有价值,项目源 ViewModel 集合也不会更新。
回答by lokusking
I've made you a minimal example of that desired CustomControl.
我已经为您提供了所需的 CustomControl 的最小示例。
The Control
控制
public class MyCustomControl : ItemsControl {
static MyCustomControl() {
DefaultStyleKeyProperty.OverrideMetadata(typeof(MyCustomControl), new FrameworkPropertyMetadata(typeof(MyCustomControl)));
}
private Button _addButton;
private TextBox _textBox;
private ListView _itemsView;
public override void OnApplyTemplate() {
this._addButton = this.GetTemplateChild("PART_AddButton") as Button;
this._textBox = this.GetTemplateChild("PART_TextBox") as TextBox;
this._itemsView = this.GetTemplateChild("PART_ListBox") as ListView;
this._addButton.Click += (sender, args) => {
(this.ItemsSource as IList<string>).Add(this._textBox.Text);
};
this._itemsView.ItemsSource = this.ItemsSource;
base.OnApplyTemplate();
}
public ICommand DeleteCommand => new RelayCommand(x => { (this.ItemsSource as IList<string>).Remove((string)x); });
}
The Template
模板
<Style TargetType="{x:Type local:MyCustomControl}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type local:MyCustomControl}">
<Border Background="{TemplateBinding Background}"
BorderBrush="{TemplateBinding BorderBrush}"
BorderThickness="{TemplateBinding BorderThickness}">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="300" />
<ColumnDefinition Width="100" />
</Grid.ColumnDefinitions>
<TextBox x:Name="PART_TextBox" Grid.Column="0" />
<Button x:Name="PART_AddButton" Grid.Column="1" Content="Add" Margin="20,0" />
</Grid>
<ListView ItemsSource="{TemplateBinding ItemsSource}" Grid.Row="1" Margin="0,25" x:Name="PART_ListBox" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" >
<ListView.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal" HorizontalAlignment="Stretch">
<TextBlock Text="{Binding}"/>
<Button Content="X" Foreground="Red"
Command="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type local:MyCustomControl}}, Path=DeleteCommand}"
CommandParameter="{Binding}" Margin="10,0,0,0"></Button>
</StackPanel>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
</Grid>
</Border>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
RelayCommand
中继命令
public class RelayCommand : ICommand
{
#region Fields
private readonly Action<object> _execute;
private readonly Predicate<object> _canExecute;
#endregion // Fields
#region Constructors
public RelayCommand(Action<object> execute, Predicate<object> canExecute = null)
{
if (execute == null)
throw new ArgumentNullException(nameof(execute));
this._execute = execute;
this._canExecute = canExecute;
}
#endregion // Constructors
#region ICommand Members
[DebuggerStepThrough]
public bool CanExecute(object parameter)
{
return this._canExecute == null || this._canExecute(parameter);
}
public event EventHandler CanExecuteChanged {
add { CommandManager.RequerySuggested += value; }
remove { CommandManager.RequerySuggested -= value; }
}
public void Execute(object parameter)
{
this._execute(parameter);
}
#endregion // ICommand Members
}
Usage
用法
<local:MyCustomControl ItemsSource="{Binding Collection}"/>
NoteDo not use a Listas your ItemsSource. Rather use an ObservableCollectionsince it notifies the View automaticly and you dont have to deal with that Update-Stuff
注意不要使用 aList作为您的 ItemsSource。而是使用 an ,ObservableCollection因为它会自动通知 View 并且您不必处理该 Update-Stuff
Cheers
干杯
回答by Sameed
Suppose this is your custom control:
假设这是您的自定义控件:
<UserControl x:Class="CustomControl.UserControl1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:local="clr-namespace:CustomControl"
mc:Ignorable="d" >
<StackPanel Width="200" Margin="15">
<TextBox Name="txtbox"/>
<Button Content="Add"
Margin="20,0" Click="Button_Click"/>
<ListBox ItemsSource="{Binding}"
Margin="0,25">
</ListBox>
</StackPanel>
And this is your Parentwindow Calling your custom control:
这是您的 Parentwindow 调用您的自定义控件:
<Window x:Class="ParentControl.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:ParentControl"
mc:Ignorable="d"
xmlns:customcontrol="clr-namespace:CustomControl;assembly=CustomControl"
Title="MainWindow" Height="350" Width="525">
<Grid>
<customcontrol:UserControl1 Name="customcontrol"></customcontrol:UserControl1>
</Grid>
you have a string collection which you want to be updated with the text in the textbox, you can do something like this: In the parent window set the DataContext of the custom control to the string collection, like this:
您有一个字符串集合,您想用文本框中的文本对其进行更新,您可以执行以下操作:在父窗口中,将自定义控件的 DataContext 设置为字符串集合,如下所示:
public MainWindow()
{
InitializeComponent();
ObservableCollection<string> stringcollection = new ObservableCollection<string>();
stringcollection.Add("String 1");
stringcollection.Add("String 2");
stringcollection.Add("String 2");
stringcollection.Add("String 3");
customcontrol.DataContext = stringcollection;
}
and in your custom control back logic add handler to the button click event and do something like this:
并在您的自定义控件返回逻辑中向按钮单击事件添加处理程序并执行以下操作:
private void Button_Click(object sender, RoutedEventArgs e)
{
var button = sender as Button;
var list = button.DataContext as ObservableCollection<string>;
list.Add(this.txtbox.Text.ToString());
}
make sure that the string collection is of Type Observable Collection, otherwise you listbox wont get updated everytime you click the add button.
确保字符串集合是 Observable Collection 类型,否则每次单击添加按钮时列表框都不会更新。
Hope it helps.
希望能帮助到你。


