Reputation: 185
In WPF, I am creating a simple custom control for my TODO program. It should do the following:
My main issues/Questions are:
Is there a better way to do this? If my control is a container for buttons AND a text box, should I not be inheriting from ListBox? Should I inherit from Control instead and make it a container?
I had something close working before, in the following code, but now I want this moved from my main Window XAML to the custom control code, and I want to be able to edit on button press:
<!-- In my MainWindow.XAML -->
<TaskDashControls:ListBoxWithAddRemove x:Name="listBoxItems" Grid.Row="1" Grid.Column="3" Grid.RowSpan="3"
ItemsSource="{Binding}">
<TaskDashControls:ListBoxWithAddRemove.ItemTemplate>
<DataTemplate>
<DockPanel>
<Button DockPanel.Dock="Left" Click="SelectItemClick">SELECT</Button>
<TextBlock x:Name="LabelDescription" Visibility="Visible" DockPanel.Dock="Left" Text="{Binding Description}" Height="25" Width="150" />
<TextBox x:Name="EditableDescription" Visibility="Collapsed" DockPanel.Dock="Left" Text="{Binding Description}" Height="25" Width="150" />
<Button DockPanel.Dock="Left" Click="EditTaskItemClick">EDIT</Button>
</DockPanel>
</DataTemplate>
</TaskDashControls:ListBoxWithAddRemove.ItemTemplate>
</TaskDashControls:ListBoxWithAddRemove>
I have now removed the DataTemplate, to move it over to the custom control:
<!-- In my MainWindow.XAML -->
<TaskDashControls:ListBoxWithAddRemove x:Name="listBoxItems" Grid.Row="1" Grid.Column="3" Grid.RowSpan="3"
ItemsSource="{Binding}"/>
Here is the custom control in Generic.XAML:
<ResourceDictionary
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:TaskDash.Controls">
<SolidColorBrush x:Key="WindowBackgroundBrush" Color="#FFF" />
<SolidColorBrush x:Key="SolidBorderBrush" Color="#888" />
<SolidColorBrush x:Key="DisabledForegroundBrush" Color="#888" />
<SolidColorBrush x:Key="DisabledBackgroundBrush" Color="#EEE" />
<SolidColorBrush x:Key="DisabledBorderBrush" Color="#AAA" />
<Style TargetType="{x:Type TextBox}">
<Setter Property="Margin" Value="2" />
</Style>
<Style x:Key="{x:Type local:ListBoxWithAddRemove}" TargetType="{x:Type local:ListBoxWithAddRemove}">
<Setter Property="Margin" Value="3" />
<Setter Property="SnapsToDevicePixels" Value="True"/>
<Setter Property="KeyboardNavigation.TabNavigation" Value="None"/>
<Setter Property="FocusVisualStyle" Value="{x:Null}"/>
<Setter Property="MinWidth" Value="120"/>
<Setter Property="MinHeight" Value="20"/>
<Setter Property="AllowDrop" Value="true"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate>
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="25" />
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<!--<Button Grid.Column="0" Grid.Row="0" x:Name="DeleteButton"
Click="DeleteControlClick">Delete</Button>
<Button Grid.Column="1" Grid.Row="0" x:Name="AddButton"
Click="AddControlClick">Add</Button>-->
<Button Grid.Column="0" Grid.Row="0" x:Name="DeleteButton">Delete</Button>
<Button Grid.Column="1" Grid.Row="0" x:Name="AddButton">Add</Button>
<Border
Grid.Column="0" Grid.Row="1" Grid.ColumnSpan="2"
Name="Border"
Background="{StaticResource WindowBackgroundBrush}"
BorderBrush="{StaticResource SolidBorderBrush}"
BorderThickness="1"
CornerRadius="2">
<ScrollViewer
Margin="0"
Focusable="false">
<StackPanel Margin="0" IsItemsHost="True" />
</ScrollViewer>
<!--<ListBox ItemTemplate="{TemplateBinding ItemTemplate}">
<DataTemplate>
<DockPanel>
<TextBlock x:Name="LabelDescription" Visibility="Visible" DockPanel.Dock="Left" Text="{Binding Description}" Height="25" Width="150" />
<TextBox x:Name="EditableDescription" DockPanel.Dock="Left" Text="{Binding Description}" Height="25" Width="150" />
</DockPanel>
</DataTemplate>
</ListBox>-->
</Border>
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
Here is my custom control class
using System;
using System.Windows;
using System.Windows.Controls;
namespace TaskDash.Controls
{
[TemplatePart(Name = "Text", Type = typeof(TextBox))]
[TemplatePart(Name = "LabelText", Type = typeof(TextBlock))]
public class TextBoxWithDescription : Control
{
static TextBoxWithDescription()
{
DefaultStyleKeyProperty.OverrideMetadata(typeof(TextBoxWithDescription), new FrameworkPropertyMetadata(typeof(TextBoxWithDescription)));
}
public TextBoxWithDescription()
{
LabelText = String.Empty;
Text = String.Empty;
}
public static readonly DependencyProperty LabelTextProperty =
DependencyProperty.Register("LabelText", typeof(string), typeof(TextBoxWithDescription),
new PropertyMetadata(string.Empty, OnLabelTextPropertyChanged));
private static void OnLabelTextPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
}
public string LabelText
{
get { return GetValue(LabelTextProperty).ToString(); ; }
set { SetValue(LabelTextProperty, value); }
}
// http://xamlcoder.com/cs/blogs/joe/archive/2007/12/13/building-custom-template-able-wpf-controls.aspx
public static readonly DependencyProperty TextProperty =
DependencyProperty.Register("Text", typeof(string), typeof(TextBoxWithDescription),
new UIPropertyMetadata(null,
new PropertyChangedCallback(OnTextChanged)
));
private static void OnTextChanged(DependencyObject o, DependencyPropertyChangedEventArgs e)
{
TextBoxWithDescription textBox = o as TextBoxWithDescription;
if (textBox != null)
textBox.OnTextChanged((String)e.OldValue, (String)e.NewValue);
}
protected virtual void OnTextChanged(String oldValue, String newValue)
{
// fire text changed event
this.Text = newValue;
this.RaiseEvent(new RoutedEventArgs(TextChangedEvent, this));
}
public string Text
{
get { return GetValue(TextProperty).ToString(); }
set { SetValue(TextProperty, value); }
}
public static readonly RoutedEvent TextChangedEvent =
EventManager.RegisterRoutedEvent("TextChanged",
RoutingStrategy.Bubble,
typeof(RoutedEventHandler),
typeof(TextBoxWithDescription));
public event RoutedEventHandler TextChanged
{
add { AddHandler(TextChangedEvent, value); }
remove { RemoveHandler(TextChangedEvent, value); }
}
public override void OnApplyTemplate()
{
base.OnApplyTemplate();
//var textBlock = (TextBlock)this.Template.FindName("LabelText", this);
//if (textBlock != null) textBlock.Text = this.LabelText;
//var textBox = (TextBox)this.Template.FindName("Text", this);
//if (textBox != null) textBox.Text = this.Text;
}
}
}
Upvotes: 2
Views: 1528
Reputation: 45096
I would create a class for TODO with Properties: String Desc, Visibility txtBox, Visibility txtBlock. Then items source for the TaskDashControls is List TODO. In xaml you can bind the visibilty property. In the TODO class you can control that when one is visible the other is not.
Upvotes: 1