How to create a custom Textbox with a TextBlock? - c#

I want to create a custom control(or user control) which has both a textblock and a textbox as in the fig below:
Both the textblock and Textbox text properties are to be bound to the database fields and be able to apply styling etc. Which is the best approach for the same?
I have come up with a solution as below:
XAML for user control:
<UserControl x:Class="TestDependency.TextBlox"
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"
x:Name="abc"
DataContext="{Binding RelativeSource={RelativeSource Self}}" >
<Grid Width="170">
<TextBlock Height="23" HorizontalAlignment="Left" Margin="0,1,0,0"
Text="{Binding Path=Caption}"
VerticalAlignment="Top" Width="52" />
<TextBox Height="25" HorizontalAlignment="Left" Margin="53,-2,0,0"
x:Name="TextBox1"
Text="{Binding Path=Value}"
VerticalAlignment="Top" Width="120" />
</Grid>
Code behind for Usercontrol:
public partial class TextBlox : UserControl
{
public TextBlox()
{
InitializeComponent();
}
public static DependencyProperty CaptionProperty = DependencyProperty.Register("Caption", typeof(string), typeof(TextBlox));
public static DependencyProperty ValueProperty = DependencyProperty.Register("Value", typeof(string), typeof(TextBlox));
public string Caption
{
get
{
return (string)GetValue(CaptionProperty);
}
set
{
SetValue(CaptionProperty, value);
}
}
public string Value
{
get
{
return (string)GetValue(ValueProperty);
}
set
{
SetValue(ValueProperty, value);
}
}
static void ValueChangedCallBack(DependencyObject property, DependencyPropertyChangedEventArgs args)
{
TextBlox inst = (TextBlox)property;
inst.TextBox1.Text = (string)args.NewValue;
}
}
XAML for actual form where Usercontrol is used:
<Grid x:Name="grdmain">
<my:TextBlox Caption="{Binding XValue, Mode=TwoWay}" Value="{Binding WindowName, Mode=TwoWay}"
HorizontalAlignment="Left" Margin="246,197,0,0" x:Name="textBlox1" VerticalAlignment="Top" />
</Grid>
Code behind:
public partial class MainWindow : Window
{
DataEntities dt = new DataEntities();
CoOrdinate oCord;
public MainWindow()
{
InitializeComponent();
Loaded += new RoutedEventHandler(MainWindow_Loaded);
}
void MainWindow_Loaded(object sender, RoutedEventArgs e)
{
oCord = dt.CoOrdinates.First();
grdmain.DataContext = oCord;
}
}
Still the binding doesnt work. But the code :
textBlox1.Caption = "test";
is working fine. where am I wrong?

Create an user control with a textblock and textbox and bind the values to that control.
<YourUserControl TextBlockText="{Binding TextBlockText}" TextBoxText="{Binding TextBoxText, Mode=TwoWay}"/>

Related

Give Name to Control inside a Object Dependency Property of an UserControl

I have an UserControl that have Object Propdp:
public partial class HeaderControl : UserControl
{
public HeaderControl()
{
InitializeComponent();
DataContext = this;
}
public static readonly DependencyProperty ControlContentProperty =
DependencyProperty.Register(nameof(ControlContent), typeof(object),
typeof(HeaderControl), new PropertyMetadata(null));
public object ControlContent
{
get { return (object)GetValue(ControlContentProperty); }
set { SetValue(ControlContentProperty, value); }
}
}
In Xaml file:
<Grid Grid.Row="1">
<ContentControl Content="{Binding ControlContent, ElementName=root}"/>
</Grid>
if i use it without give a Name to the Button inside it works:
<ctrl:HeaderContorl >
<ctrl:HeaderContorl.ControlContent>
<Button Content="Hallooo" FontSize="40"
Foreground="Black" Height="100"/>
</ctrl:HeaderContorl.ControlContent>
</ctrl:HeaderContorl>
But if i name the Button inside it not works:
<ctrl:HeaderContorl >
<ctrl:HeaderContorl.ControlContent>
<Button x:Name="Btn" Content="Hallooo" FontSize="40"
Foreground="Black" Height="100"/>
</ctrl:HeaderContorl.ControlContent>
</ctrl:HeaderContorl>
Can someone please tell me why I can't name the button inside?

How to override the text style in a custom user control?

I have a user control that that consist of
a. A textblock whose content is bound to UserLabel
b. A textbox whose content is bound to UserValue.
When I add this user control to the Main Window, I want to add a subscript in the UserLabel, but do not know how to do that.
I want to do something like this (THE FOLLOWING CODE DOES NOT WORK. IT IS WHAT I WANT TO DO):
<Window
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:local="clr-namespace:MyNamespace"
Title="MyControl Sample"
Height="300"
Width="300">
<StackPanel>
<local:MyControl>
<UserLabel.Text>
Subscript<Run BaselineAlignment="Subscript" FontSize="12pt">This</Run>
<UserLabel.Text>
<local:MyControl>
</StackPanel>
</Window>
How can I achieve something like that?
Here is the XAML:
<UserControl x:Class="TEST.MyControl"
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"
mc:Ignorable="d"
d:DesignHeight="450" d:DesignWidth="800"
x:Name="parent">
<StackPanel Width="100" Orientation="Horizontal"
DataContext="{Binding ElementName=parent}">
<!-- User Label -->
<TextBlock Width="200" Name="UserLabel"
Text="{Binding Path=UserLabel}" >
</TextBlock>
<!-- User Input -->
<TextBox Width="100" Name="MetricValue"
Text="{Binding Path=UserValue}"/>
</StackPanel>
</UserControl>
and here is the CODE BEHIND:
/// <summary>
/// Interaction logic for MyControl.xaml
/// </summary>
public partial class MyControl: UserControl
{
public MyControl()
{
InitializeComponent();
}
#region User Label DP
public static readonly DependencyProperty UserLabelProperty =
DependencyProperty.Register("UserLabel",
typeof(string),
typeof(MyControl),
new PropertyMetadata(""));
public string UserLabel
{
get { return GetValue(UserLabelProperty) as String; }
set { SetValue(UserLabelProperty, value); }
}
#endregion // User Label DP
#region UserValue DP
public static readonly DependencyProperty UserValueProperty =
DependencyProperty.Register("UserValue",
typeof(string),
typeof(MyControl),
new PropertyMetadata(""));
public string UserValue
{
get { return GetValue(UserValueProperty) as String; }
set { SetValue(UserValueProperty, value); }
}
#endregion // UserValue DP
}
Make UserLabel a TextBlock instead of a string that has no concept of Run elements:
#region User Label DP
public static readonly DependencyProperty UserLabelProperty =
DependencyProperty.Register("UserLabel",
typeof(TextBlock),
typeof(MyControl));
public TextBlock UserLabel
{
get { return GetValue(UserLabelProperty) as TextBlock; }
set { SetValue(UserLabelProperty, value); }
}
#endregion // User Label DP
UserControl XAML:
<!-- User Label -->
<ContentControl Width="200" Content="{Binding UserLabel, ElementName=parent}" />
Window XAML:
<StackPanel>
<local:MyControl>
<local:MyControl.UserLabel>
<TextBlock>
<Run FontSize="12pt">Subscript</Run>
<Run BaselineAlignment="Subscript" FontSize="12pt">This</Run>
</TextBlock>
</local:MyControl.UserLabel>
</local:MyControl>
</StackPanel>

Binding to DependencyProperty doesn't update LongListSelector items as expected

I have one UserControl LetterInRowUserControl with LongListSelector and ItemTemplate in xaml part
<UserControl>
...
<UserControl.Resources>
<DataTemplate x:Key="itemTemplate">
<local:LetterControl x:Name="letterControl" VerticalAlignment="Top" Width="50" Letter="{Binding}"/>
</DataTemplate>
</UserControl.Resources>
<Grid x:Name="LayoutRoot">
<phone:LongListSelector x:Name="lls" LayoutMode="List" ItemTemplate="{StaticResource itemTemplate}" />
</Grid>
</UserControl>
cs part:
public partial class LetterInRowUserControl : UserControl
{
public LetterInRowUserControl()
{
InitializeComponent();
LetterControl.TextChanged += (o, ev) =>
{
var conv = new StringToListConverter();
ContainsLetters = (string)conv.ConvertBack(lls.ItemsSource, typeof(string), null, CultureInfo.CurrentCulture);
};
}
public static readonly DependencyProperty ContainsLettersProperty =
DependencyProperty.Register("ContainsLetters", typeof (string), typeof (LetterInRowUserControl), new PropertyMetadata(default(string),
(o, args) =>
{
var control = (LetterInRowUserControl) o;
var conv = new StringToListConverter();
control.lls.ItemsSource = (ObservableCollection<string>)conv.Convert(args.NewValue, typeof(string), null, CultureInfo.CurrentCulture);
}));
public string ContainsLetters
{
get
{
return (string) GetValue(ContainsLettersProperty);
}
set
{
SetValue(ContainsLettersProperty, value);
}
}
}
then I have second Usercontrol - LetterControl which is inside itemstemplate of LetterInRowUserControl
xaml part:
<UserControl>
...
<Grid x:Name="LayoutRoot">
<Grid>
<Button x:Name="hidden" Height="0" Width="0"/>
<TextBox x:Name="textBox"
TextWrapping="Wrap" VerticalAlignment="Top" Height="84" Margin="-12" FontFamily="Segoe WP Semibold" FontSize="33.333" TextAlignment="Center" GotFocus="textBox_GotFocus" LostFocus="textBox_LostFocus" MaxLength="1" TextChanged="textBox_TextChanged"/>
</Grid>
</Grid>
</UserControl>
and cs part:
public partial class LetterControl : UserControl
{
public static event TextChangedEventHandler TextChanged;
public static readonly DependencyProperty LetterProperty =
DependencyProperty.Register("Letter", typeof(string), typeof(LetterControl), new PropertyMetadata(default(string),
(o, args) =>
{
var control = (LetterControl)o;
control.textBox.Text = (string)args.NewValue;
}));
public string Letter
{
get { return (string)GetValue(LetterProperty); }
set
{
SetValue(LetterProperty, value);
}
}
public LetterControl()
{
InitializeComponent();
}
private void textBox_GotFocus(object sender, RoutedEventArgs e)
{
textBox.SelectAll();
}
private void textBox_LostFocus(object sender, RoutedEventArgs e)
{
textBox.Text = textBox.Text.ToUpper();
}
private void textBox_TextChanged(object sender, TextChangedEventArgs e)
{
SetValue(LetterProperty,textBox.Text);
if(textBox.Text.Length>=1)
hidden.Focus();
if (TextChanged != null) TextChanged.Invoke(sender, e);
}
}
Basically there are two UserControls: LetterInRowUserControl and LetterControl.
LetterInRowUserControl has LongListSelector with LetterControl inside its ItemTemplate.
The problem is that if I change Property Letter from inside LetterControl, it doesn't affect ItemSource in LongListSelector in LetterInRowUserControl. Conversely (if I change ItemSource directly) it works without problems.
/intended to one Windows Phone 8 App
... something like listbox with textboxes of one letter - problem is that if I edit a letter ItemSource of listbox doesn't change.
EDIT: After hard trying I have succeeded. And my code is working. Main problem was that I was using ObservableCollection<string> and not ObservableCollection<CustomObjectWithINotifyPropChangedImplementation>. So the value wasn't automatically changed (ObservableCollection did not fulfill its function).

WPF UserControl Properties

In the code below, I have a UserControl that contains an ellipse and a textblock. I'd like to create a reusable control that I can bind to that allows me to set the text based on a string, and changes the fill color between Red/Green based on a boolean.
I can do this now by digging deep into the markup and using some complex binding, but I want to reuse this control in a list and it seemed easier to create a control for the purpose. However, I am not sure where to go next and if I should be creating dependency-properties that tie to the values for Fill and Text, or what.
<UserControl
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"
mc:Ignorable="d"
x:Class="Herp.Derp.View.DeliveryStatusIndicator"
x:Name="UserControl"
d:DesignWidth="91" d:DesignHeight="35">
<Grid x:Name="LayoutRoot">
<StackPanel Orientation="Horizontal">
<Ellipse Width="35" Height="35" Fill="Green">
<Ellipse.OpacityMask>
<VisualBrush Stretch="Fill" Visual="{StaticResource appbar_location_circle}"/>
</Ellipse.OpacityMask>
</Ellipse>
<TextBlock Style="{StaticResource Heading2}"
VerticalAlignment="Center" Margin="3,0,0,0">
<Run Text="FRONT"/>
</TextBlock>
</StackPanel>
</Grid>
</UserControl>
here how you can achieve this
UserControl
/// <summary>
/// Interaction logic for UserControl1.xaml
/// </summary>
public partial class UserControl1 : UserControl
{
public UserControl1()
{
InitializeComponent();
}
public static readonly DependencyProperty FrontTextProperty = DependencyProperty.Register( "FrontText", typeof(string),typeof(UserControl1), new FrameworkPropertyMetadata(string.Empty));
public string FrontText
{
get { return (string)GetValue(FrontTextProperty); }
set {
SetValue(FrontTextProperty, value);
frontBlock.Text = value;
}
}
public static readonly DependencyProperty EllipseStateProperty = DependencyProperty.Register("EllipseState", typeof(bool), typeof(UserControl1), new FrameworkPropertyMetadata(false));
public bool EllipseState
{
get { return (bool)GetValue(EllipseStateProperty); }
set
{
SetValue(EllipseStateProperty, value);
if (value)
{
ellipse.Fill = new SolidColorBrush( Colors.Green);
}
else
{
ellipse.Fill = new SolidColorBrush(Colors.Red);
}
}
}
}
MainWindow
<Window
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:WpfApplication1" x:Class="WpfApplication1.MainWindow"
Title="MainWindow" Height="350" Width="525">
<Grid>
<local:UserControl1 EllipseState="{Binding yourProperty }"/>
<CheckBox Content="CheckBox" HorizontalAlignment="Left" Margin="207,94,0,0" VerticalAlignment="Top"/>
</Grid>
</Window>
Yes, to create properties that "parent" XAML can assign bindings to, you need to create aDependencyProperty for each field that you want to bind to.
You would then bind your user control xaml to the backing property for the DP.
Here's what I got for a working solution:
public partial class DeliveryStatusIndicator : UserControl
{
public DeliveryStatusIndicator()
{
InitializeComponent();
}
public static readonly DependencyProperty DeliveryDescriptionProperty = DependencyProperty.Register("DeliveryDescription", typeof(string), typeof(DeliveryStatusIndicator), new FrameworkPropertyMetadata("Default", DescriptionChangedEventHandler));
private static void DescriptionChangedEventHandler(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
((DeliveryStatusIndicator)d).Desc.Text = (string)e.NewValue;
}
public string DeliveryDescription
{
get { return (string)GetValue(DeliveryDescriptionProperty); }
set
{
SetValue(DeliveryDescriptionProperty, value);
}
}
public static readonly DependencyProperty DeliveryStatusProperty = DependencyProperty.Register("DeliveryStatus", typeof(bool), typeof(DeliveryStatusIndicator), new FrameworkPropertyMetadata(false, StatusChangedEventHandler));
private static void StatusChangedEventHandler(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
((DeliveryStatusIndicator)d).Indicator.Fill = (bool)e.NewValue ? new SolidColorBrush(Colors.Green) : new SolidColorBrush(Colors.Red);
}
public bool DeliveryStatus
{
get { return (bool)GetValue(DeliveryStatusProperty); }
set
{
SetValue(DeliveryStatusProperty, value);
}
}
}

WPF Composite Controls

I'm trying to create a reusable UserControl in WPF that has a Label and a TextBox. I want to add properties to my UserControl to bubble up the Text fields of both child controls up to the parent for easy binding. I read that I need to a little bit of hocus pocus by adding owners to DependencyProperties. Here is my code now. It seems close but not quite right. Any ideas?
Here is the Xaml:
<UserControl x:Class="MAAD.AircraftExit.Visual.LabelTextBox"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Height="20" Width="300">
<DockPanel>
<TextBlock Text="{Binding Path=Label, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type UserControl}}}" DockPanel.Dock="Left" TextAlignment="Right" Width="122" />
<TextBlock Text=": " DockPanel.Dock="Left"/>
<TextBox Text="{Binding Path=Text, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type UserControl}}}" />
</DockPanel>
</UserControl>
And the code behind:
public partial class LabelTextBox : UserControl
{
public static readonly DependencyProperty LabelProperty = DependencyProperty.Register("Label", typeof(string), typeof(LabelTextBox));
public string Label
{
get { return (string)GetValue(LabelProperty); }
set { SetValue(LabelProperty, value); }
}
public static readonly DependencyProperty TextProperty = DependencyProperty.Register("Text", typeof(string), typeof(LabelTextBox));
public string Text
{
get { return (string)GetValue(TextProperty); }
set { SetValue(LabelTextBox.TextProperty, value); }
}
public LabelTextBox()
{
InitializeComponent();
ClearValue(HeightProperty);
ClearValue(WidthProperty);
}
}
Edit: Here is the final working code. I switched over to relative source binding.
Binding is really the way to go:
XAML:
<UserControl x:Class="testapp.LabelTextBox "
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Height="300" Width="300" x:Name="This">
<DockPanel>
<TextBlock DockPanel.Dock="Left" TextAlignment="Right" Width="70" Name="label" Text="{Binding Label, ElementName=This}" />
<TextBlock Text=": " DockPanel.Dock="Left" />
<TextBox Name="textBox" Text="{Binding Text, ElementName=This}" />
</DockPanel>
Code Behind:
public partial class LabelTextBox : UserControl
{
public LabelTextBox()
{
InitializeComponent();
Label = "Label";
Text = "Text";
}
public static readonly DependencyProperty LabelProperty = DependencyProperty.Register("Label", typeof(string), typeof(LabelTextBox), new FrameworkPropertyMetadata(LabelPropertyChangedCallback));
private static void LabelPropertyChangedCallback(DependencyObject controlInstance, DependencyPropertyChangedEventArgs args)
{
}
public string Label
{
get { return (string) GetValue(LabelProperty); }
set { SetValue(LabelProperty, value); }
}
public static readonly DependencyProperty TextProperty = DependencyProperty.Register("Text", typeof(string), typeof(LabelTextBox), new FrameworkPropertyMetadata(TextPropertyChangedCallback));
private static void TextPropertyChangedCallback(DependencyObject controlInstance, DependencyPropertyChangedEventArgs args)
{
}
public string Text
{
get { return (string) GetValue(TextProperty); }
set { SetValue(LabelTextBox.TextProperty, value); }
}
}
I haven't looked into exactly why your implementation isn't working, but I don't really understand why you're doing it that way. Why not just define the dependency properties you need on the UserControl and then bind to them?
public static readonly DependencyProperty LabelTextProperty = ...;
And then in your XAML:
<Label Content="{Binding LabelText}"/>

Categories

Resources