WPF DatePicker make separator fixed and always visible - wpf

I am developing a WPF application in which I would like to use the default DatePicker control. I also want to let the user insert manually the date, but I want to prevent the separator ("/") to be deleted by the user. (more precisely, even if the DatePicker's textbox is "empty", the separators should be still there)
Can this be done without creating a new Custom Control? Thank you!

I have made the following sample:
<DatePicker HorizontalAlignment="Left" Margin="132,118,0,0" VerticalAlignment="Top" Width="204" Name="DatePicker"
SelectedDateChanged="DatePicker_OnSelectedDateChanged">
<DatePicker.Resources>
<Style TargetType="{x:Type DatePickerTextBox}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition/>
<ColumnDefinition/>
<ColumnDefinition/>
<ColumnDefinition/>
<ColumnDefinition/>
</Grid.ColumnDefinitions>
<TextBox x:Name="TextBox1" Grid.Column="0"
Style="{StaticResource DatePickerTextBoxStyle}"
TextChanged="OnTextboxTextChanged1" PreviewTextInput="OnPreviewTextInput1"/>
<Label Grid.Column="1" Content="/" FontSize="18" HorizontalAlignment="Center"/>
<TextBox x:Name="TextBox2" Grid.Column="2" Style="{StaticResource DatePickerTextBoxStyle}"
TextChanged="OnTextboxTextChanged2" PreviewTextInput="OnPreviewTextInput2"/>
<Label Grid.Column="3" Content="/" FontSize="18" HorizontalAlignment="Center"/>
<TextBox x:Name="TextBox3" Grid.Column="4" Style="{StaticResource DatePickerTextBoxStyle}"
TextChanged="OnTextboxTextChanged3" PreviewTextInput="OnPreviewTextInput3"/>
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</DatePicker.Resources>
</DatePicker>
And in your codebehind:
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
}
private static void TrimText(TextBox textbox)
{
textbox.Text = textbox.Text.Trim();
if (textbox.Text.Length == 2) textbox.Text = textbox.Text.PadLeft(2, '0');
textbox.CaretIndex = textbox.Text.Length;
}
private void OnTextboxTextChanged1(object sender, TextChangedEventArgs e)
{
var textbox = sender as TextBox;
if (textbox == null) return;
TrimText(textbox);
if (textbox.Text.Length != 2) return;
var datePickerTxtBox = DatePicker.Template.FindName("PART_TextBox", DatePicker) as DatePickerTextBox;
var secondTxtbox = datePickerTxtBox.Template.FindName("TextBox2", datePickerTxtBox) as TextBox;
secondTxtbox.Focus();
}
private void OnTextboxTextChanged2(object sender, TextChangedEventArgs e)
{
var textbox = sender as TextBox;
if (textbox == null) return;
TrimText(textbox);
if (textbox.Text.Length != 2) return;
var datePickerTxtBox = DatePicker.Template.FindName("PART_TextBox", DatePicker) as DatePickerTextBox;
var thirdTxtbox = datePickerTxtBox.Template.FindName("TextBox3", datePickerTxtBox) as TextBox;
thirdTxtbox.Focus();
}
private void OnTextboxTextChanged3(object sender, TextChangedEventArgs e)
{
var textbox = sender as TextBox;
if (textbox == null) return;
TrimText(textbox);
if (textbox.Text.Length != 2) return;
var datePickerTxtBox = DatePicker.Template.FindName("PART_TextBox", DatePicker) as DatePickerTextBox;
var firstTxtbox = datePickerTxtBox.Template.FindName("TextBox1", datePickerTxtBox) as TextBox;
var secondTxtbox = datePickerTxtBox.Template.FindName("TextBox2", datePickerTxtBox) as TextBox;
DateTime date;
var text = firstTxtbox.Text + secondTxtbox.Text + textbox.Text;
if (!DateTime.TryParseExact(text,"ddMMyy",null,DateTimeStyles.None, out date))
firstTxtbox.Text = secondTxtbox.Text = textbox.Text = string.Empty;
else DatePicker.DisplayDate = date;
}
private void OnPreviewTextInput1(object sender, TextCompositionEventArgs e)
{
e.Handled = !(new Regex("[0-9]+").IsMatch(e.Text));
}
private void OnPreviewTextInput2(object sender, TextCompositionEventArgs e)
{
e.Handled = !(new Regex("[0-9]+").IsMatch(e.Text));
}
private void OnPreviewTextInput3(object sender, TextCompositionEventArgs e)
{
e.Handled = !(new Regex("[0-9]+").IsMatch(e.Text));
}
private void DatePicker_OnSelectedDateChanged(object sender, SelectionChangedEventArgs e)
{
var newDate = DateTime.Parse(e.Source.ToString());
DatePicker.DisplayDate = newDate;
var datePickerTxtBox = DatePicker.Template.FindName("PART_TextBox", DatePicker) as DatePickerTextBox;
var firstTxtbox = datePickerTxtBox.Template.FindName("TextBox1", datePickerTxtBox) as TextBox;
var secondTxtbox = datePickerTxtBox.Template.FindName("TextBox2", datePickerTxtBox) as TextBox;
var thirdTxtbox = datePickerTxtBox.Template.FindName("TextBox3", datePickerTxtBox) as TextBox;
firstTxtbox.Text = DatePicker.DisplayDate.ToString("dd");
secondTxtbox.Text = DatePicker.DisplayDate.ToString("MM");
thirdTxtbox.Text = DatePicker.DisplayDate.ToString("yy");
}
}
This is just a sample of how you may work around this. It is lacking of some validation, mainly in the inner textboxes used to hold year, month and day values. Nevertheless it is something as you possibly want
EDIT>>> Also the codebehind must be improved for production as I have lot of repeated code. But this is just an example.
EDIT2>>>> This is how it looks:

Related

WPF Drop event is firing twice

2nd Edit
so removing the Panel.ZIndex properties from the control template resolved this issue for me, giving me 1 drop event.
including them triggers two drop events.
can any one answer me why though?
id love to know why z index ?
Original Question :
I am trying to add a custom object (state) to a canvas called MainCanvas on the MainWindow.
I am trying to drag a state object from a wrap panel and drop it onto the canvas.
the code works but there are two items being added.
I know there are two because I can move the two item around the canvas.
I have searched existing answers and added e.Handled=true, but still adds two items
I tried using Drop event and PreviewDrop Event on MainCanvas, no difference.
Cam someone help as to how I can make it so that only 1 item gets added?
the maincanvas exists at design time
a new state is created at runtime at the drop event.
Here is the OnMouseMove handler for the state
protected override void OnMouseMove(MouseEventArgs e)
{
base.OnMouseMove(e);
if (e.LeftButton == MouseButtonState.Pressed)
{
var parent = VisualTreeHelper.GetParent(this);
if (parent as WrapPanel != null)
{
DataObject dragData = new DataObject();
dragData.SetData(DataFormats.StringFormat, this.ItemType);
DragDrop.DoDragDrop(this, dragData, DragDropEffects.Copy);
}
}
e.Handled = true;
}
Within the Code Behind I have set the following events for the canvas:
private void MainCanvas_DragEnter(object sender, DragEventArgs e)
{
if (e.Data.GetDataPresent(DataFormats.Text))
e.Effects = DragDropEffects.Copy;
else
e.Effects = DragDropEffects.None;
e.Handled = true;
}
private void MainCanvas_Drop(object sender, DragEventArgs e)
{
var itemType = e.Data.GetData(typeof(string));
switch (itemType)
{
case "state":
var pos = e.GetPosition(this.MainCanvas);
State item = new State();
item.Template = (ControlTemplate)FindResource("StateViewModelControlTemplate");
this.MainCanvas.Children.Add(item);
Canvas.SetLeft(item, pos.X);
Canvas.SetTop(item, pos.Y);
e.Handled = true;
break;
default:
break;
}
e.Handled = true;
}
Finally here is the xaml for the Main Canvas
<Canvas x:Name="MainCanvas" x:Name="MainCanvas"
DockPanel.Dock="Top"
Background="#666"
Height="600"
Margin="4"
AllowDrop="True"
DragEnter="MainCanvas_DragEnter"
Drop="MainCanvas_Drop"/>
Edit:
ok so after lupus' response i went back and reconstructed everything from scratch in a separate temp project
<ControlTemplate x:Key="StateViewModelControlTemplate" TargetType="{x:Type vm:State}">
<Grid Width="100" Height="60">
<!--
If I comment out the following Thumb
the drop event will only trigger once
If i leave it in then it triggers twice
Move Thumb is derived from thumb
-->
<local:MoveThumb Panel.ZIndex="99"
x:Name="StateViewModelMoveThumb"
DataContext="{Binding RelativeSource={RelativeSource TemplatedParent}}"
Opacity="0"/>
<Border Panel.ZIndex="98"
Margin="4"
Padding="4"
BorderBrush="white"
BorderThickness="2"
CornerRadius="5">
<Border.Background>
<LinearGradientBrush EndPoint="0.5,1" StartPoint="0.5,0">
<GradientStop Color="#FF59C7D4" Offset="0.5"/>
<GradientStop Color="#FF075A64" Offset="0"/>
<GradientStop Color="#FF00626E" Offset="1"/>
</LinearGradientBrush>
</Border.Background>
<ContentPresenter HorizontalAlignment="Center" VerticalAlignment="Center" Content="{TemplateBinding StateName}"/>
</Border>
</Grid>
</ControlTemplate>
By the way what I trying to do is very loosely based on the following article: https://www.codeproject.com/Articles/22952/WPF-Diagram-Designer-Part-1
I tried your code, and I cannot reproduce your issue. Changes:
private void MainCanvas_Drop(object sender, DragEventArgs e)
{
var itemType = e.Data.GetData(typeof(string));
switch (itemType)
{
var pos = e.GetPosition(this.MainCanvas);
Border item = new Border()
{
Width = 10,
Height = 10,
Background = Brushes.Red
};
//item.Template = (ControlTemplate)FindResource("StateViewModelControlTemplate");
this.MainCanvas.Children.Add(item);
...
}
protected override void OnMouseMove(MouseEventArgs e)
{
base.OnMouseMove(e);
if (e.LeftButton == MouseButtonState.Pressed)
{
DataObject dragData = new DataObject();
dragData.SetData(DataFormats.StringFormat, "state");
DragDrop.DoDragDrop(this, dragData, DragDropEffects.Copy);
}
e.Handled = true;
}
and in xaml,
<Window ...
Title="MainWindow" Height="450" Width="800">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<Canvas x:Name="MainCanvas" Grid.Column="0"
DockPanel.Dock="Top"
Background="#666"
Height="600"
Margin="4"
AllowDrop="True"
DragEnter="MainCanvas_DragEnter"
Drop="MainCanvas_Drop"/>
<Grid Grid.Column="1" Background="Red"/>
</Grid>
Have not touch the other piece of code. Everytime I drag from the Grid to the Canvas, I get one Border item at the drop position.
So maybe the problem is not in the code you posted, but in the code left out or commented.
So I eventually got this working and here is how
Here is the front end xaml on the mainwindow
<cc:DiagramCanvas x:Name="MainCanvas"
DockPanel.Dock="Top"
Margin="0"
MinHeight="450"
AllowDrop="True" Background="White">
</cc:DiagramCanvas>
Here is the custom canvas object and the drag drop handler
public class DiagramCanvas : Canvas
{
public DiagramCanvas()
{
this.Drop += DoDrop;
this.DragEnter += MainCanvas_DragEnter;
}
readonly MainWindow mainWin = (MainWindow)Application.Current.MainWindow;
#region works dont touch
public void DoDrop(object sender, DragEventArgs e)
{
var mainWin = (MainWindow)App.Current.MainWindow;
DragDropHandler<StateVM>.Instance.Drop(sender, e);
}
private void MainCanvas_DragEnter(object sender, DragEventArgs e)
{
if (e.Data.GetDataPresent(DataFormats.Text))
e.Effects = DragDropEffects.Copy;
else
e.Effects = DragDropEffects.None;
e.Handled = true;
}
#endregion
//other code here
}
Here is the drag drop handler singleton
public sealed class DragDropHandler<T> where T : Control
{
#region singleton
private static DragDropHandler<T> instance = null;
private static readonly object padlock = new object();
DragDropHandler()
{
}
public static DragDropHandler<T> Instance
{
get
{
lock (padlock)
{
if (instance == null)
{
instance = new DragDropHandler<T>();
}
return instance;
}
}
private set
{
instance = value;
}
}
#endregion
public static bool IsDragging { get; set; }
public static WrapPanel AllowedDragSource { get; set; }
readonly MainWindow mainWin = (MainWindow)Application.Current.MainWindow;
public static void CreateInstance(WrapPanel allowedSource)
{
if (DragDropHandler<T>.IsDragging == false)
{
instance = new DragDropHandler<T>();
DragDropHandler<T>.AllowedDragSource = allowedSource;
}
}
public void Drag(object sender, MouseEventArgs e)
{
if (sender as T == null
|| mainWin.Radio_EditStates.IsChecked == false
|| e.LeftButton != MouseButtonState.Pressed
|| IsDragging == true)
{
e.Handled = true;
return;
}
var item = (T)sender;
if (Control.ReferenceEquals(item.Parent, AllowedDragSource) == false)
{
e.Handled = true;
return;
}
IsDragging = true;
DragDrop.DoDragDrop(((StateVM)sender), new DataObject(((StateVM)sender)), DragDropEffects.Copy);
IsDragging = false;
e.Handled = true;
}
public void Drop(object sender, DragEventArgs e)
{
var mainWin = (MainWindow)App.Current.MainWindow;
if (IsDragging)
{
//TODO: Switch here to handle different shapes
var pos = e.GetPosition(mainWin.MainCanvas);
//
Canvas.SetLeft(item, pos.X.RoundDownTo10());
Canvas.SetTop(item, pos.Y.RoundDownTo10());
//update main win observalbe collections to inclue the item dropped
IsDragging = false;
e.Handled = true;
DestroyInstance();
}
}
private static void DestroyInstance()
{
DragDropHandler<T>.Instance = null;
}
}
Here is the on mouse move code for the item you are dragging
protected override void OnMouseMove(MouseEventArgs e)
{
base.OnMouseMove(e);
if (e.LeftButton == MouseButtonState.Pressed && Control.ReferenceEquals(this.Parent, mainWin.libraryContainer))
{
DragDropHandler<StateVM>.CreateInstance(mainWin.libraryContainer);
if (DragDropHandler<StateVM>.Instance != null)
{
DragDropHandler<StateVM>.Instance.Drag(this, e);
}
}
}

how to bind listview selected item to textbox dynamically in wpf

I have 2 columns in my Grid. I will create Button and textbox dynamically in each row. For the dynamic button click, I will show one popup window. The Popup window has some ListviewItems. this is my requirement:
1.If I select any Listview item, it should be displayed on the corresponding textbox.
for example, If it is in the 3rd row, I want to bind the ListviewItem in textbox which is positioned in (Row3, Column1)
this is my xaml:
<Grid>
<DockPanel HorizontalAlignment="Left" Height="165" Margin="40,100,0,0" VerticalAlignment="Top" Width="620">
<ScrollViewer>
<Grid x:Name="grid1" Height="auto" Width="580"/>
</ScrollViewer>
</DockPanel>
<Button x:Name="btn_addnewrow" Content="Add" HorizontalAlignment="Left" Margin="69,43,0,0" VerticalAlignment="Top" Width="89" Height="31" Click="btn_addnewrow_Click"/>
<Popup Name="popup" IsOpen="False" Placement="Mouse" VerticalOffset="15" HorizontalOffset="0" Margin="124,122,107,65">
<Border BorderBrush="Black" BorderThickness="1" Background="Coral">
<StackPanel Orientation="Horizontal" Height="143">
<ListView Margin="10,10,0,0" Name="ListView1" HorizontalAlignment="Left"
VerticalAlignment="Top" Width="194" Height="133" MouseDoubleClick="ListView1_MouseDoubleClick">
<ListViewItem Content="Coffie"></ListViewItem>
<ListViewItem Content="Tea"></ListViewItem>
<ListViewItem Content="Orange Juice"></ListViewItem>
<ListViewItem Content="Milk"></ListViewItem>
<ListViewItem Content="Iced Tea"></ListViewItem>
<ListViewItem Content="Mango Shake"></ListViewItem>
</ListView>
</StackPanel>
</Border>
</Popup>
</Grid>
and this is my code:
public partial class DummyTypeofControl : Window
{
public DummyTypeofControl()
{
InitializeComponent();
}
public int count = 0;
public Button btn1;
public Button btn2;
public TextBox txt1;
private void btn_addnewrow_Click(object sender, RoutedEventArgs e)
{
//Creating Rows..
RowDefinition row0 = new RowDefinition();
row0.Height = new GridLength(40);
grid1.RowDefinitions.Add(row0);
//Creating columns..
ColumnDefinition col0 = new ColumnDefinition();
ColumnDefinition col1 = new ColumnDefinition();
col0.Width = new GridLength(50);
col1.Width = new GridLength(70);
grid1.ColumnDefinitions.Add(col0);
grid1.ColumnDefinitions.Add(col1);
int i = count;
//1st Column button
btn1 = new Button();
btn1.Margin = new Thickness(10, 10, 0, 0);
btn1.BorderThickness = new Thickness(0);
btn1.Name = "btn1_" + i;
Grid.SetRow(btn1, i);
Grid.SetColumn(btn1, 0);
btn1.Click += btnBindList_Click;
grid1.Children.Add(btn1);
//2nd column Textbox
txt1 = new TextBox();
txt1.Margin = new Thickness(10, 10, 0, 0);
txt1.Name = "txt" + i;
Grid.SetRow(txt1, i);
Grid.SetColumn(txt1, 1);
grid1.Children.Add(txt1);
count++;
}
private void btnBindList_Click(object sender, RoutedEventArgs e)
{
popup.IsOpen = true;
}
private void ListView1_MouseDoubleClick(object sender, MouseButtonEventArgs e)
{
?
?
?
?
popup.IsOpen = false;
}
}
I want to take the rows count and bind listview itms to the corresponding rows textbox dynamically.. i dont know how to continue further.. could any one please help me?
Did not quite understand what you wanted, but give this a try.. a bit unconventional.
private void btn_addnewrow_Click(object sender, RoutedEventArgs e)
{
.....
//let the button know about the textbox
btn1.Tag = txt1;
}
Then, everytime you click on
private void btnBindList_Click(object sender, RoutedEventArgs e)
{
//get the linked textbox and keep it stored int txt1
txt1 = ((Button)sender).Tag as TextBox;
popup.IsOpen = true;
}
Then, when you click on on the listview
private void ListView1_MouseDoubleClick(object sender, MouseButtonEventArgs e)
{
txt1.Text = (ListView1.SelectedItem as ListViewItem).Content.ToString();
popup.IsOpen = false;
}
There are better and cleaner ways to do this

Referencing a databound ContextMenu inside a LongListSelector ItemTemplate - Windows Phone

I am writing a Silverlight for Windows Phone 7.5 app.
I want to reference the ContextMenu inside my LongListSelector because I want to set .IsOpen to false as soon as the ContextMenu Click event is called. My thought was that this should happen automatically but it does not.
One of my MenuItem's sets the visibility of a <Grid> from collapsed to visible which mimics a PopUp. Whilst the code executes fine and the Visibility does indeed change. The UI of the app does not show the Grid unless the ContextMenu closes.
My XAML of the LongListSelector which contains a ContextMenu called Menu that I wish to reference in the ContextMenuItem Click event.
<toolkit:LongListSelector x:Name="moviesLongList" Background="Transparent" IsFlatList="False" GroupHeaderTemplate="{StaticResource GroupHeaderTemplate}" GroupItemTemplate="{StaticResource GroupItemTemplate}" SelectionChanged="moviesLongList_SelectionChanged" GroupViewClosing="moviesLongList_GroupViewClosing" GroupViewOpened="moviesLongList_GroupViewOpened">
<toolkit:LongListSelector.GroupItemsPanel>
<ItemsPanelTemplate>
<toolkit:WrapPanel/>
</ItemsPanelTemplate>
</toolkit:LongListSelector.GroupItemsPanel>
<toolkit:LongListSelector.ItemTemplate>
<DataTemplate>
<StackPanel Height="91" Margin="20,0,0,20" Orientation="Horizontal">
<toolkit:ContextMenuService.ContextMenu >
<toolkit:ContextMenu x:Name="Menu" Opened="ContextMenu_Opened" Loaded="Menu_Loaded" Unloaded="Menu_Unloaded">
<toolkit:ContextMenu.ItemTemplate>
<DataTemplate>
<toolkit:MenuItem Header="{Binding}" Click="ContextMenuButton_Click" LostFocus="MenuItem_LostFocus" />
</DataTemplate>
</toolkit:ContextMenu.ItemTemplate>
</toolkit:ContextMenu>
</toolkit:ContextMenuService.ContextMenu>
<Border HorizontalAlignment="Left" Width="61" Height="91" Background="{Binding ID, Converter={StaticResource ThumbImageConvert}}" />
<StackPanel Orientation="Vertical" HorizontalAlignment="Left" Width="395">
<TextBlock x:Name="titleTextBox" Text="{Binding Title, Converter={StaticResource TitleConvert}}" Margin="6,0,6,0" d:LayoutOverrides="Width" FontSize="{StaticResource PhoneFontSizeLarge}" VerticalAlignment="Top" HorizontalAlignment="Left"/>
<TextBlock x:Name="yearTextBox" Text="{Binding Year}" Margin="12,0,0,0" HorizontalAlignment="Left" FontSize="{StaticResource PhoneFontSizeMedium}" Foreground="{StaticResource PhoneSubtleBrush}" />
</StackPanel>
</StackPanel>
</DataTemplate>
</toolkit:LongListSelector.ItemTemplate>
</toolkit:LongListSelector>
My code behind ContextMenuItem Click event
private void ContextMenuButton_Click(object sender, RoutedEventArgs e)
{
//
// This is where I want to set Menu.IsOpen = false to close the ContextMenu.
//
if ((sender as MenuItem).Header.ToString() == "lend movie")
{
DisableAppBarIcons();
LendPopUpOverlay.Visibility = System.Windows.Visibility.Visible;
}
if ((sender as MenuItem).Header.ToString() == "return to collection")
{
... Do stuff
}
if ((sender as MenuItem).Header.ToString() == "add to boxset")
{
... Do stuff
}
if ((sender as MenuItem).Header.ToString() == "delete")
{
... Do stuff
}
}
I set the ItemSource of the ContextMenu in the ContextMenu_Opened event. The fields are both of type List<String>.
private void ContextMenu_Opened(object sender, RoutedEventArgs e)
{
LentMovieObj = (sender as ContextMenu).DataContext as Movies;
if (LentMovieObj.IsLent)
{
(sender as ContextMenu).ItemsSource = menuItemsReturn;
}
else
{
(sender as ContextMenu).ItemsSource = menuItemsLendOut;
}
}
Not sure why the ContextMenu is not closing, but here are two solutions. The first is to get the parent of the MenuItem.
private T GetParentOfType<T>(DependencyObject obj) where T : class
{
if (obj == null) return null;
var parent = VisualTreeHelper.GetParent(obj);
while (parent != null)
{
if (parent is T) return parent as T;
parent = VisualTreeHelper.GetParent(parent);
}
return null;
}
Then get the Menu from your click handler
var menu = GetParentOfType<ContextMenu>(sender as MenuItem);
menu.IsOpen = false;
The second solution is to bind IsOpen to a backing viewmodel
<toolkit:ContextMenuService.ContextMenu >
<toolkit:ContextMenu x:Name="Menu" Opened="ContextMenu_Opened" Loaded="Menu_Loaded" Unloaded="Menu_Unloaded" IsOpen="{Binding IsOpen}" ItemsSource="{Binding Items}">
<toolkit:ContextMenu.ItemTemplate>
<DataTemplate>
<toolkit:MenuItem Header="{Binding}" Click="ContextMenuButton_Click" LostFocus="MenuItem_LostFocus" />
</DataTemplate>
</toolkit:ContextMenu.ItemTemplate>
</toolkit:ContextMenu>
</toolkit:ContextMenuService.ContextMenu>
Change your open event:
private void ContextMenu_Opened(object sender, RoutedEventArgs e)
{
LentMovieObj = (sender as ContextMenu).DataContext as Movies;
if (LentMovieObj.IsLent)
{
(sender as ContextMenu).DataContext = new ContextMenuViewModel(menuItemsReturn);
}
else
{
(sender as ContextMenu).DataContext = ContextMenuViewModel(menuItemsLendOut);
}
}
Then a viewmodel
public class ContextMenuViewModel : INotifyPropertyChanged
{
private bool _isOpen = true;
public ContextMenuViewModel(IEnumerable<string> items)
{
Items = items;
}
public event PropertyChangedEventHandler PropertyChanged;
public bool IsOpen
{
get { return _isOpen; }
set { _isOpen = value; OnPropertyChanged("IsOpen"); }
}
public IEnumerable<String> Items { get; set; }
protected virtual void OnPropertyChanged(string propertyName)
{
var handler = PropertyChanged;
if (handler != null)
{
handler(this, new PropertyChangedEventArgs(propertyName));
}
}
}
Then set the IsOpen property of your ViewModel to false;

Set events for new UIelements on runtime

I'm kinda confused with some problem, I'm doing a project where the user should be able to design questions with radio buttons, combo box, etc (kinda like toolbox from VS10 to design your XAML).
So far I can drag and drop an UIElement that I previously created, problem comes when the user creates a new element from my toolbox, I can't find the way to make that new UIElement to get the same events from my previosly created UIElement. Take a look at the code
<Window x:Class="WpfApplication1.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow" Height="350" Width="525">
<Grid>
<Canvas Height="190" HorizontalAlignment="Left" Margin="158,41,0,0" Name="canvas1" VerticalAlignment="Top" Width="322" AllowDrop="True">
<Button Content="PROBANDO" Height="23" Name="button" Width="75" Canvas.Left="113" Canvas.Top="43" PreviewMouseDown="button_PreviewMouseDown" PreviewMouseMove="button_PreviewMouseMove" MouseUp="button_MouseUp" IsEnabled="True" />
<TextBlock Canvas.Left="99" Canvas.Top="147" Height="23" Name="textBlock" Text="" Width="107" />
</Canvas>
<ListBox Height="190" Name="listBox" Width="126" Margin="12,41,365,80" >
<ListBoxItem Content="Radio Button" Selected="radio_Selected" Name="radio" />
<ListBoxItem Content="Text" Selected="text_Selected" Name="text" />
<ListBoxItem Content="Combo Box" Name="combo" Selected="combo_Selected" />
</ListBox>
</Grid>
</Window>
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
}
Point p;
private void button_MouseUp(object sender, MouseButtonEventArgs e)
{
button.ReleaseMouseCapture();
}
private void button_PreviewMouseDown(object sender, MouseButtonEventArgs e)
{
button.CaptureMouse();
p = e.GetPosition(canvas1);
}
private void button_PreviewMouseMove(object sender, MouseEventArgs e)
{
Point x = e.GetPosition(canvas1);
if (e.LeftButton == MouseButtonState.Pressed)
{
Canvas.SetLeft(button, Canvas.GetLeft(button) + (x.X - p.X));
Canvas.SetTop(button, Canvas.GetTop(button) + (x.Y - p.Y));
}
p = x;
}
private void generic_PreviewMouseDown(UIElement sender, MouseEventArgs e)
{
Point x = e.GetPosition(canvas1);
if (e.LeftButton == MouseButtonState.Pressed)
{
Canvas.SetLeft(sender, Canvas.GetLeft(sender) + (x.X - p.X));
Canvas.SetTop(sender, Canvas.GetTop(sender) + (x.Y - p.Y));
}
p = x;
}
private void radio_Selected(object sender, RoutedEventArgs e)
{
RadioButton newRadio = new RadioButton();
canvas1.Children.Add(newRadio);
newRadio.PreviewMouseDown += generic_PreviewMouseDown(newRadio,?????);
textBlock.Text = listBox.SelectedIndex.ToString();
}
private void text_Selected(object sender, RoutedEventArgs e)
{
TextBox newText = new TextBox();
canvas1.Children.Add(newText);
textBlock.Text = (String)listBox.SelectedIndex.ToString();
}
private void combo_Selected(object sender, RoutedEventArgs e)
{
Console.Write("Combo");
textBlock.Text = (String)listBox.SelectedIndex.ToString();
}
}
Thanks!
If all you want to do is handle the mouse down on the new RadioButton, change this line:
newRadio.PreviewMouseDown += generic_PreviewMouseDown(newRadio,?????);
To this:
newRadio.PreviewMouseDown += generic_PreviewMouseDown;
Edit
And then you need to change the generic_PreviewMouseDown to the following:
private void generic_PreviewMouseDown(object sender, MouseEventArgs e)
{
UIElement elem = sender as UIElement;
Point x = e.GetPosition(canvas1);
if (e.LeftButton == MouseButtonState.Pressed)
{
Canvas.SetLeft(elem, Canvas.GetLeft(elem) + (x.X - p.X));
Canvas.SetTop(elem, Canvas.GetTop(elem) + (x.Y - p.Y));
}
p = x;
}

WPF Template: AdornedElement not showing!

I want to add some elements to a TextBox by using a Template with the extra elements and the original TextBox inserted in the right spot. I'm trying to use the AdornedElementPlaceholder just like you would do when making a Validation.ErrorTemplate But the AdornedElement is not showing up. I have simplified the example as much as possible:
<TextBox Text="Border me with my Template">
<TextBox.Template>
<ControlTemplate TargetType="{x:Type TextBox}">
<Border BorderBrush="Green" BorderThickness="1">
<AdornedElementPlaceholder/>
</Border>
</ControlTemplate>
</TextBox.Template>
</TextBox>
The result is just a green box around the space that should be my textbox!
Unfortunately, that's just not how it works. However, it's not much more difficult than that. If you want to add a green border around a text box by changing the control template, it's going to look a bit more like this:
<ControlTemplate TargetType="TextBox">
<Border x:Name="Border"
CornerRadius="2"
Background="{TemplateBinding Background}"
BorderBrush="Green"
BorderThickness="1"
SnapsToDevicePixels="True">
<ScrollViewer x:Name="PART_ContentHost"/>
</Border>
</ControlTemplate>
The important part in there is the ScrollViewer named PART_ContentHost. The TextBox looks for that guy when the template is applied and uses it to host the text, caret, etc. What I think you're missing is that when you override the Template for an element, you're overriding the entire control template. It's unfortunate that you can't just change bits and pieces, but that's the truth of the matter.
Of course, if you want to maintain the original look and feel of the TextBox, such that it still looks like a Win7 TextBox for instance, you'd need to do a bit more in the ControlTemplate.
For what it's worth, it looks like the template you were trying to apply would work if you're talking about using an Adorner. It's similar to how the validation templates work in WPF, but that's a whole-nother story.
Oh, and for a much simpler way to change the border to green, you should be able to just set the BorderBrush property on the TextBox itself. Of course, I really don't know exactly what you're going for.
--
HTH
Dusty
I ended up doing a Custom Control based on a HeaderedContent Control.
It will allow the user to click or hoover over some content and then show a bubble containing some other or the same content.
Usage:
<JsCustomControls:BaloonBox LabelText="{Binding Note}" WaterMark="Click to write Note" Type="ClickToShow">
<JsCustomControls:BaloonBox.Content>
<TextBox AcceptsReturn="True" Text="{Binding Path=Note}" TextWrapping="Wrap"></TextBox>
</JsCustomControls:BaloonBox.Content>
</JsCustomControls:BaloonBox>
The code for the User control:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Controls.Primitives;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Threading;
namespace JsCustomControls
{
public enum BaloonBoxTypeEnum
{
ClickToShow,
MouseOverToShow,
Manual
}
[TemplatePart(Name = BaloonBox.HeaderElement, Type = typeof(ContentPresenter))]
[TemplatePart(Name = BaloonBox.ContentElement, Type = typeof(ContentPresenter))]
[TemplatePart(Name = BaloonBox.PopUpElement, Type = typeof(Popup))]
[TemplatePart(Name=BaloonBox.LabelElement,Type=typeof(Label))]
public class BaloonBox : HeaderedContentControl
{
DispatcherTimer PopupTimer = new DispatcherTimer();
private const string HeaderElement = "PART_HeaderContentControl";
private const string ContentElement = "PART_ContenContentControl";
private const string PopUpElement = "PART_PopUp";
private const string LabelElement = "PART_HeaderLabel";
private ContentPresenter headerContentControl;
private ContentPresenter contentContentControl;
private Popup popUp;
private Label headerLabel;
static BaloonBox()
{
DefaultStyleKeyProperty.OverrideMetadata(typeof(BaloonBox), new FrameworkPropertyMetadata(typeof(BaloonBox)));
}
public override void OnApplyTemplate()
{
base.OnApplyTemplate();
headerContentControl = GetTemplateChild(HeaderElement) as ContentPresenter;
contentContentControl = GetTemplateChild(ContentElement) as ContentPresenter;
popUp = GetTemplateChild(PopUpElement) as Popup;
headerLabel = GetTemplateChild(LabelElement) as Label;
if (headerContentControl != null) headerContentControl.MouseDown += new MouseButtonEventHandler(headerContentControl_MouseDown);
if(headerLabel!=null)headerLabel.MouseDown+=new MouseButtonEventHandler(headerContentControl_MouseDown);
if (headerContentControl != null) headerContentControl.MouseMove += new MouseEventHandler(headerContentControl_MouseMove);
if(headerLabel!=null)headerLabel.MouseMove+=new MouseEventHandler(headerContentControl_MouseMove);
PopupTimer = new DispatcherTimer();
PopupTimer.Tick += new EventHandler(PopupTimer_Tick);
if(string.IsNullOrEmpty(LabelText))
{
if (headerLabel != null) headerLabel.Foreground = Brushes.Gray;
if (headerLabel != null) headerLabel.Content = WaterMark;
}
else
{
if (headerLabel != null) headerLabel.Foreground = Brushes.Black;
if (headerLabel != null) headerLabel.Content = LabelText;
}
}
void headerContentControl_MouseMove(object sender, MouseEventArgs e)
{
if (Type == BaloonBoxTypeEnum.MouseOverToShow)
{
if (popUp != null) popUp.IsOpen = true;
PopupTimer.Interval = new TimeSpan(0, 0, 0, 2);
PopupTimer.Start();
}
}
void headerContentControl_MouseDown(object sender, MouseButtonEventArgs e)
{
if (Type == BaloonBoxTypeEnum.ClickToShow)
{
if (popUp != null) popUp.IsOpen = true;
PopupTimer.Interval = new TimeSpan(0, 0, 0, 3);
PopupTimer.Start();
}
}
void PopupTimer_Tick(object sender, EventArgs e)
{
if (!headerContentControl.IsMouseOver && !contentContentControl.IsMouseOver && !contentContentControl.IsKeyboardFocusWithin)
{
PopupTimer.Stop();
popUp.IsOpen = false;
}
}
public static readonly DependencyProperty IsOpenProperty = DependencyProperty.Register("IsOpen",
typeof (bool),
typeof (BaloonBox),
new FrameworkPropertyMetadata
(new PropertyChangedCallback
(OnIsOpenChanged)));
public bool IsOpen
{
get { return (bool) GetValue(IsOpenProperty); }
set{SetValue(IsOpenProperty,value);}
}
private static void OnIsOpenChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
BaloonBox baloonBox = (BaloonBox)d;
baloonBox.popUp.IsOpen =(bool)e.NewValue;
}
public static readonly DependencyProperty WaterMarkProperty = DependencyProperty.Register("WaterMark",
typeof (string),
typeof (BaloonBox),
new FrameworkPropertyMetadata
(new PropertyChangedCallback
(OnWatermarkChanged)));
public string WaterMark
{
get { return (string)GetValue(WaterMarkProperty); }
set { SetValue(WaterMarkProperty,value); }
}
private static void OnWatermarkChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
}
public static readonly DependencyProperty LabelTextProperty = DependencyProperty.Register("LabelText",
typeof (string),
typeof (BaloonBox)
,new FrameworkPropertyMetadata(new PropertyChangedCallback(OnLabelTextChanged)));
public string LabelText
{
get { return (string) GetValue(LabelTextProperty); }
set
{
SetValue(LabelTextProperty,value);
headerLabel.Content = value;
}
}
private static void OnLabelTextChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
BaloonBox baloonBox = (BaloonBox)d;
if (string.IsNullOrEmpty(e.NewValue.ToString()))
{
if (baloonBox.headerLabel != null) baloonBox.headerLabel.Foreground = Brushes.Gray;
if (baloonBox.headerLabel != null) baloonBox.headerLabel.Content = baloonBox.WaterMark;
}
else
{
if (baloonBox.headerLabel != null) baloonBox.headerLabel.Foreground = Brushes.Black;
if (baloonBox.headerLabel != null) baloonBox.headerLabel.Content = e.NewValue;
}
}
public static readonly DependencyProperty BaloonBoxTypeProperty = DependencyProperty.Register(
"BaloonBoxType", typeof(BaloonBoxTypeEnum), typeof(BaloonBox), new FrameworkPropertyMetadata(new PropertyChangedCallback(OnBaloonBoxTypeChanged)));
public BaloonBoxTypeEnum Type
{
get { return (BaloonBoxTypeEnum) GetValue(BaloonBoxTypeProperty);}
set { SetValue(BaloonBoxTypeProperty,value);}
}
private static void OnBaloonBoxTypeChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
//who cares?
}
}
}
</Border>
<Popup x:Name="PART_PopUp" HorizontalOffset="-50" VerticalOffset="-5" AllowsTransparency="True" IsOpen="False" PopupAnimation="Slide" PlacementTarget="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=Header}">
<Grid Height="150" Width="250" >
<Grid.ColumnDefinitions>
<ColumnDefinition Width="2"></ColumnDefinition>
<ColumnDefinition Width="0.050*"></ColumnDefinition>
<ColumnDefinition Width="0.900*"></ColumnDefinition>
<ColumnDefinition Width="0.050*"></ColumnDefinition>
<ColumnDefinition Width="2"></ColumnDefinition>
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="2"></RowDefinition>
<RowDefinition Height="0.300*"></RowDefinition>
<RowDefinition Height="0.700*"></RowDefinition>
<RowDefinition Height="0.100*"></RowDefinition>
<RowDefinition Height="2"></RowDefinition>
</Grid.RowDefinitions>
<Path Grid.Row="1" Grid.RowSpan="3" Grid.Column="1" Grid.ColumnSpan="3" Data="M79,279 L119,279 135,263 135,279 319,279 319,368.5 78.5,368.5 z" Fill="#FFFDFDB3" Stretch="Fill" Stroke="Black" UseLayoutRounding="False">
</Path>
<ScrollViewer Grid.Row="2" Grid.Column="2" Grid.RowSpan="1" HorizontalScrollBarVisibility="Auto" VerticalScrollBarVisibility="Auto">
<ContentPresenter x:Name="PART_ContenContentControl" Content="{Binding Content, RelativeSource={RelativeSource TemplatedParent}}"/>
</ScrollViewer>
</Grid>
</Popup>
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>

Resources