Rewrite "button.Click += ..." using ICommand in WPF - c#

I am using an external SDK.
namespace ProSimSDK
{
public class ArmedFailure
{
...
public static event ArmedFailureEventDelegate onNew;
public void Reset();
...
}
}
namespace ProSimSDK
{
public delegate void ArmedFailureEventDelegate(ArmedFailure armedFailure);
}
I have some trouble when I try to rewrite some Winform code by WPF. In Winform:
public Form1()
{
InitializeComponent();
ArmedFailure.onNew += new ArmedFailureEventDelegate(ArmedFailure_onNew);
}
// This function will be called when a new armedFailure is received
void ArmedFailure_onNew(ArmedFailure armedFailure)
{
//Here is the code I need to rewrite in WPF.
removeButton.Click += new EventHandler(delegate(object sender, EventArgs e)
{
failure.Reset();
});
}
In WPF, I use a listbox. With some guide, I am using ListBox Template and Command.
In Window1.xaml:
<DataTemplate x:Key="ListBoxItemTemplate">
<Grid>
<TextBlock x:Name="TB" Margin="5,10,5,5" Grid.Column="2" Height="23" Text="{Binding}" VerticalAlignment="Top" />
<Button HorizontalAlignment="Right" Grid.Column="3" Margin="500,10,5,0" CommandParameter="{Binding}" Command="{Binding ElementName=UC_Failures_Setting, Path=OnClickCommand}" Width="80" Click="Button_Click">remove</Button>
</Grid>
</DataTemplate>
<ListBox x:Name="listbox" ItemTemplate="{StaticResource ListBoxItemTemplate}" Margin="0,661,982,0" SelectionChanged="ListBox_SelectionChanged">
Window1.xaml.cs
public Window1()
{
InitializeComponent();
//How to implement the same functionality of "removeButton.Click += new EventHandler(delegate(object sender, EventArgs e) {failure.Reset();});" shown in Winform???
OnClickCommand = new ActionCommand(x => listbox.Items.Remove(x));
}
ActionCommand.cs:
public class ActionCommand: ICommand
{
private readonly Action<object> Action;
private readonly Predicate<object> Predicate;
public ActionCommand(Action<object> action) : this(action, x => true)
{
}
public ActionCommand(Action<object> action, Predicate<object> predicate)
{
Action = action;
Predicate = predicate;
}
public bool CanExecute(object parameter)
{
return Predicate(parameter);
}
public void Execute(object parameter)
{
Action(parameter);
}
public event EventHandler CanExecuteChanged
{
add
{
CommandManager.RequerySuggested += value;
}
remove
{
CommandManager.RequerySuggested -= value;
}
}
}
How does the button in my listbox implement the same functionality of
removeButton.Click += new EventHandler(delegate(object sender, EventArgs e)
{ failure.Reset(); });
shown in Winform? In WPF I cannot write it this way. Thanks.

if ListBox is populated with ArmedFailure items, then the parameter which command receives, should be ArmedFailure item.
OnClickCommand = new ActionCommand
(
x =>
{
var failure = (ArmedFailure)x;
failure.Reset();
listbox.Items.Remove(x);
}
);
everything that was in Button.Click handler in WinForms becomes part of ICommand.Execute in wpf

Related

How do I update my UI without stuttering / deadlocks

I have a WPF application which has a DataGrid that is bound to to a ObservableCollection<string> named "Customers" and I also have a button which is bound to a command which starts a some what heavy task. it simulates adding a bunch of entries to the DataGridas fast as possible.
The issue I am facing is that while it's adding entries to the DataGrid there appears to be stutters and some times deadlocks when trying to move the UI as it's adding entries to the DataGrid.
From my understanding it's because I am updating the DataGrid on the UI thread using Application.Current.Dispatcher.Invoke(() => { /*Update OC*/ });
and even tho they might be small updates to the UI, a lot of them might cause stuttering, now that's my understanding and I might be completely wrong.
My question is.. Is there a way to make this async or reduce the stuttering / deadlocks some other way?
XAML UI
<Window.DataContext>
<local:MainViewModel/>
</Window.DataContext>
<Grid>
<StackPanel>
<DataGrid ItemsSource="{Binding Customers}" AutoGenerateColumns="False"
Width="300" Height="200">
<DataGrid.Columns>
<DataGridTemplateColumn Header="Image" Width="SizeToCells" IsReadOnly="True">
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<TextBlock Text="{Binding }" />
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
</DataGrid.Columns>
</DataGrid>
<Button Width="100"
Height="25"
Content="Start"
Command="{Binding StartAddingCommand}"/>
</StackPanel>
<Border VerticalAlignment="Bottom"
Height="25" Background="Orange">
<TextBlock Text="{Binding Customers.Count}"
HorizontalAlignment="Center" VerticalAlignment="Center"/>
</Border>
</Grid>
MainViewModel
class MainViewModel : ObservableObject
{
public ObservableCollection<string> Customers { get; set; }
public RelayCommand StartAddingCommand { get; set; }
public MainViewModel()
{
Customers = new ObservableCollection<string>();
StartAddingCommand = new RelayCommand(o => AddCustomers(), o => true);
}
private void AddCustomers()
{
Task.Run(() =>
{
try
{
foreach (var VARIABLE in GetHTML("https://pastebin.com/raw/gG540TEj"))
{
Application.Current.Dispatcher.Invoke(() =>
{
Customers.Add(VARIABLE.ToString());
});
}
}
catch (Exception e)
{
Console.WriteLine(e);
throw;
}
});
}
public string GetHTML(string page)
{
WebClient client = new WebClient();
return client.DownloadString(page);
}
}
And the RelayCommand & ObservableObject are just generic ones.
RelayCommand
public class RelayCommand : ICommand
{
private Action<object> execute;
private Func<object, bool> canExecute;
public event EventHandler CanExecuteChanged
{
add { CommandManager.RequerySuggested += value; }
remove { CommandManager.RequerySuggested -= value; }
}
public RelayCommand(Action<object> execute, Func<object, bool> canExecute = null)
{
this.execute = execute;
this.canExecute = canExecute;
}
public bool CanExecute(object parameter)
{
return this.canExecute == null || this.canExecute(parameter);
}
public void Execute(object parameter)
{
this.execute(parameter);
}
}
ObservableObject
class ObservableObject : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
[NotifyPropertyChangedInvocator]
protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
}
Doing a foreach with Dispatcher.Invoke without any delay will of course block the UI.
You should definitely have an async version of your GetHTML method and write the AddCustomers like shown below. Use for example one of the Get...Async methods of the HttpClient class.
private async Task AddCustomers()
{
try
{
foreach (var result in await GetHTMLAsync("https://pastebin.com/raw/gG540TEj"))
{
Customers.Add(result.ToString());
}
}
catch (Exception e)
{
Debug.WriteLine(e);
throw;
}
}
Then await the method in the command action:
StartAddingCommand = new RelayCommand(async o => await AddCustomers(), o => true);

Command Binding in WPF cannot read value of property

i have the following code:
XAML Snippet:
<TextBox HorizontalAlignment="Left" Height="23" Margin="10,57,0,0" TextWrapping="Wrap" Text="{Binding Name}" VerticalAlignment="Top" Width="140">
<TextBox.DataContext>
<ViewModels:FilterViewModel/>
</TextBox.DataContext>
</TextBox>
<Button Content="Filtern" HorizontalAlignment="Left" Margin="420,57,0,0" VerticalAlignment="Top" Width="75" Command="{Binding FilterButton}" CommandParameter="{Binding Filter}">
<Button.DataContext>
<ViewModels:FilterViewModel/>
</Button.DataContext>
</Button>
FilterViewModel.cs:
class Button : ICommand
{
public delegate void ICommandOnExecute(object parameter);
public delegate bool ICommandOnCanExecute(object parameter);
private ICommandOnExecute _execute;
private ICommandOnCanExecute _canExecute;
public Button(ICommandOnExecute onExecuteMethod, ICommandOnCanExecute onCanExecuteMethod)
{
_execute = onExecuteMethod;
_canExecute = onCanExecuteMethod;
}
public event EventHandler CanExecuteChanged
{
add { CommandManager.RequerySuggested += value; }
remove { CommandManager.RequerySuggested -= value; }
}
public bool CanExecute(object parameter)
{
return _canExecute.Invoke(parameter);
}
public void Execute(object parameter)
{
_execute.Invoke(parameter);
}
}
class FilterViewModel
{
public ICommand FilterButton { get; set; }
public FilterViewModel()
{
this.FilterButton = new Button(FilterExecute, canExecute);
}
public bool canExecute(object parameter)
{
return true;
}
public void FilterExecute(object paramter)
{
Console.WriteLine("Test: " + name);
}
private String name;
public String Name
{
get
{
return name;
}
set
{
Console.WriteLine(value);
name = value;
}
}
}
So when i click the button i want the content of the textbox printed to the console. e.g. input = "123" -> output should be "Test: 123".
However it doesn't matter what i am writing into the textbox, the result is always only the output: "Test: ". The value of the property "name" is ignored completely.
Thanks for your help!
You seem to be working with two instances of the view model. Move the definition to the MainWindow (or similar top-level parent) containing the TextBox and the Button. The DataContext value is then inherited by all child elements.
<Window.DataContext>
<ViewModels:FilterViewModel />
</Window.DataContext>
Then you can remove the definitions for the TextBox and the Button.

Updating textbox from Button click C#

I have the following textbox
<TextBox Grid.Column="1"
Grid.Row="1"
Name="groupAddressBox"
Width ="80"
Text="{Binding Path=GroupAddress, Converter={StaticResource groupAddressConverter}}"/>
When I change the text manually, it's all good.
But when I try to do this via a button
private void Test_Click(object sender, RoutedEventArgs e)
{
groupAddressBox.Text = "0/0/1";
}
Although the text changes, the source is not updated, and when I click on ok, it recognizes the value that was there before the change.
I cannot upgrade the source straight away, so I prefer to do this this way.
Is there something that can help me force the source upgrade via this way?
Based on your question, I tried to create a Simple Example of MVVM Pattern with very basic functionality. Please do necessary change to XAML and CS file as I took the highlighted code only.
Helper Classes
public abstract class ViewModelBase : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
protected virtual void OnPropertyChanged(string propName)
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(propName));
}
}
}
public class CommandHandler : ICommand
{
public event EventHandler CanExecuteChanged { add { } remove { } }
private Action<object> action;
private bool canExecute;
public CommandHandler(Action<object> action, bool canExecute)
{
this.action = action;
this.canExecute = canExecute;
}
public bool CanExecute(object parameter)
{
return canExecute;
}
public void Execute(object parameter)
{
action(parameter);
}
}
ViewModel
public class ViewModel : ViewModelBase
{
private string groupAddress;
public string GroupAddress
{
get
{
return groupAddress;
}
set
{
if(value != groupAddress)
{
groupAddress = value;
OnPropertyChanged("GroupAddress");
}
}
}
public ViewModel()
{
}
private ICommand clickCommand;
public ICommand ClickCommand
{
get
{
return clickCommand ?? (clickCommand = new CommandHandler(() => MyAction(), true));
}
}
public void MyAction()
{
GroupAddress = "New Group Address";
}
}
Window Xaml
<TextBox Grid.Column="1" Grid.Row="1" Width ="80"
Text="{Binding GroupAddress, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"/>
<Button Content="Push" Style="{StaticResource TransparentButtonStyle}"
Margin="5" Command="{Binding ClickCommand}"/>
Window Xaml cs
ViewModel vm = new ViewModel();
this.DataContext = vm;

How do I add item to a list when I select the item from a listview and click add button in the UI on WPF

I'm a newbie so excuse my question if it's too fade or if it's unclear.
any way, In my UI (WPF), i have a ListView that i created containing an observable collection of Type Collection = new ObservableCollection<type> and i have two Buttons "Add" & "Delete" I want to do this:
1-Whenever i select an item from my ListView in the UI(just click on it) , and click the "Add" button, the item is stored in a List called Scenario (Scenario = new List<type>).
2- Whenever i click the "Delete" button the Scenario list becomes empty.
I've tried something out but it doesn't work like it should, i can only add one item to the list Scenario and then it is blocked (when debugging) in
public bool CanExecute(object parameter)
{
return _canExecute == null || _canExecute(parameter);
}
Can someone tell me why? and how to fix it?
As for the "Delete" Button i didn't get to it yet because the other one doesn't work properly.
if you can propose a new solution or a solution for this problem i would be so thankful.
This is what i've done so far.
This is the code in the MainWindowModel :
private ObservableCollection<Type> _collection,_scenario;
public MainWindowModel()
{
Collection = new ObservableCollection<type>();
Scenario=new ObservableCollection<Type>();
DeleteCommand = new RelayCommand(o => DeleteExecute());
AddTypeCommand = new RelayCommand(o => AddTypeExecute());
}
private Type _isSelected;
public Type IsSelected;
{
get { return _isSelected; }
set
{
if (_isSelected != value)
{
_isSelected = value;
RaisePropertyChanged(nameof(IsSelected));
}
}
}
public ICommand DeleteCommand
{
get;
private set;
}
private RelayCommand _addTypeCommand;
public ICommand AddTypeCommand
{
get
{
if (_addTypeCommand == null)
{
_addTypeCommand = new RelayCommand(o => AddTypeExecute());
}
return _addTypeCommand;
}
set { }
}
private void DeleteExecute()
{
Scenario.Clear(); // Would this Work ?
}
private bool CanExecuteAddTypeCommand()
{
return true;
}
private void AddTypeExecute()
{
if (IsSelected != null)
{
Scenario.Add(IsSelected);
}
}
public ObservableCollection<Type> collection
{
get { return _collection; }
set { SetPropertyAndFireEvent(ref _collection, value); }
}
public ObservableCollection<Type> Scenario
{
get { return _scenario; }
set { SetPropertyAndFireEvent(ref _scenario, value); }
}
as for the MainWindowModel
<Window.DataContext>
<viewModels:MainWindowModel />
</Window.DataContext>
<Grid>
<ListView Grid.Row="2"
Grid.Column="0"
ItemsSource="{Binding Collection}"
SelectedItem="{Binding IsSelected}">
<ListView.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding Name}"/>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
<Button Command="{Binding AddTypeCommand}"
Width="100"
Height="100"
Content="Add"
Grid.Row="0"
Grid.Column="2"/>
<Button Command="{Binding DeleteCommand}"
Content="Delete"
Width="100"
Height="100"
Grid.Row="2"
Grid.Column="2" />
</Grid>
As for the RelayCommand.cs
public class RelayCommand : ICommand
{
private readonly Action<object> _execute;
private readonly Func<object, bool> _canExecute;
//Notifies the Button bounded to the ICommand that the value returned by CanExecute has changed
public event EventHandler CanExecuteChanged
{
//raised whenever the commandmanager thinks that something has changed that will affect the ability of commands to execute
add { CommandManager.RequerySuggested += value; }
remove { CommandManager.RequerySuggested -= value; }
}
public RelayCommand(Action<object> execute, Func<object, bool> canExecute = null)
{
_execute = execute;
_canExecute = canExecute;
}
public bool CanExecute(object parameter)
{
return _canExecute == null || _canExecute(parameter);
}
public void Execute(object parameter)
{
_execute(parameter);
}
}
Try passing selectedItem as parameter for command,you dont pass anything and try to add...
name your ListView:
<ListView x:Name="listView"
and pass selectedItem as commandParameter
<Button Command="{Binding AddTypeCommand}"
CommandParameter="{Binding ElementName=listView, Path=SelectedItem}"
Width="100"
Height="100"
Content="Add"
Grid.Row="0"
Grid.Column="2" />
and then do your logic for adding, now you have parameter to add to your list.
EDIT: Here is some code that works, as i have understand that u need something like this.
ViewModel _> where all collection and command are created:
public class TestVM : INotifyPropertyChanged
{
public TestVM()
{
ListOne = new ObservableCollection<string>()
{
"str1","str2","str3"
};
// command
AddTypeCommand = new RelayCommand(OnAddExecute);
DeleteTypeCommand = new RelayCommand(OnDeleteExecuted);
}
private void OnDeleteExecuted()
{
ListTwo.Clear();
}
private void OnAddExecute()
{
if (SelectedItem != null)
{
ListTwo.Add(SelectedItem);
}
}
private string _selectedItem;
public string SelectedItem
{
get { return _selectedItem; }
set
{
if (_selectedItem != value)
{
_selectedItem = value;
OnPropertyChanged();
}
}
}
private ObservableCollection<string> _listOne;
public ObservableCollection<string> ListOne
{
get
{
return _listOne;
}
set
{
if (_listOne != value)
{
_listOne = value;
OnPropertyChanged();
}
}
}
public ObservableCollection<string> ListTwo { get; set; } = new ObservableCollection<string>();
public RelayCommand AddTypeCommand { get; private set; }
public RelayCommand DeleteTypeCommand { get; private set; }
public event PropertyChangedEventHandler PropertyChanged = delegate { };
public virtual void OnPropertyChanged([CallerMemberName] string propertyName = "")
{
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
}
RellayCommand how i implement it:
public class RelayCommand : ICommand
{
private Action _executeMethod;
private Func<bool> _canExecuteMethod;
#region RelayCommand ctor
public RelayCommand(Action executeMethod)
{
_executeMethod = executeMethod;
}
public RelayCommand(Action executeMethod, Func<bool> canExecuteMethod)
{
_executeMethod = executeMethod;
_canExecuteMethod = canExecuteMethod;
}
#endregion
public void RaiseCanExecuteChanged()
{
CanExecuteChanged(this, EventArgs.Empty);
}
#region ICommand Members
bool ICommand.CanExecute(object parameter)
{
if (_canExecuteMethod != null)
return _canExecuteMethod();
if (_executeMethod != null)
return true;
return false;
}
void ICommand.Execute(object parameter)
{
if (_executeMethod != null)
_executeMethod();
}
public event EventHandler CanExecuteChanged = delegate { };
#endregion
}
//--------------------------------------------------------------------------------------------
public class RelayCommand<T> : ICommand
{
private Action<T> _executeMethod;
private Func<T, bool> _canExecuteMethod;
#region RelayCommand ctor
public RelayCommand(Action<T> executeMethod)
{
_executeMethod = executeMethod;
}
public RelayCommand(Action<T> executeMethod, Func<T, bool> canExecuteMethod)
{
_executeMethod = executeMethod;
_canExecuteMethod = canExecuteMethod;
}
#endregion
public void RaiseCanExecuteChanged()
{
CanExecuteChanged(this, EventArgs.Empty);
}
#region ICommand Members
bool ICommand.CanExecute(object parameter)
{
var Tparam = (T)parameter;
if (_canExecuteMethod != null)
return _canExecuteMethod(Tparam);
if (_executeMethod != null)
return true;
return false;
}
void ICommand.Execute(object parameter)
{
if (_executeMethod != null)
_executeMethod((T)parameter);
}
public event EventHandler CanExecuteChanged = delegate { };
#endregion
}
And MainWindow.xaml just to show purpose. Selecting on one item in 1rst list and pressing button Add will add it to second ListView. DeleteButton will clear second list.
<Window x:Class="WpfApp5.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:WpfApp5"
mc:Ignorable="d"
Title="MainWindow"
Height="350"
Width="525">
<Window.DataContext>
<local:TestVM />
</Window.DataContext>
<Grid>
<ListView x:Name="listViewOne"
ItemsSource="{Binding ListOne}"
SelectedItem="{Binding SelectedItem,Mode=TwoWay}"
Width="100"
Height="200"
Margin="17,17,400,105" />
<ListView x:Name="listViewTwo"
ItemsSource="{Binding ListTwo}"
Width="100"
Height="200"
Margin="339,17,78,105" />
<Button Command="{Binding AddTypeCommand}"
Content="Add"
Grid.Row="0"
Margin="208,111,198,178" />
<Button Command="{Binding DeleteTypeCommand}"
Content="Delete"
Grid.Row="0"
Margin="208,157,198,132" />
</Grid>
</Window>

Usercontrol not showing in designer

I have a custom user control:
<UserControl Name="ddTextBox" x:Class="UserControlsLibrary.DDTextBox"
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:DesignWidth="250" FontFamily="Tahoma" FontSize="14" MinHeight="25" Height="275">
<StackPanel>
<TextBox Name="ControlText" Height="25" HorizontalAlignment="Stretch" VerticalAlignment="Top" Text="{Binding Path=Text, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"/>
<ListBox Name="ControlList" VerticalAlignment="Top" MaxHeight="250" HorizontalAlignment="Stretch" Visibility="Collapsed" ItemsSource="{Binding Path=DList, UpdateSourceTrigger=PropertyChanged}">
<ListBox.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Vertical">
<TextBlock Text="{Binding}"/>
</StackPanel>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
</StackPanel>
</UserControl>
With the code behind:
using System;
using System.Collections;
using System.Collections.Specialized;
using System.ComponentModel;
using System.Linq;
using System.Runtime.CompilerServices;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Input;
namespace UserControlsLibrary
{
public partial class DDTextBox : UserControl, INotifyPropertyChanged
{
private string _text;
public string Text { get => _text ?? string.Empty; set { _text = value; OnPropertyChanged(); } }
public DDTextBox()
{
InitializeComponent();
ControlText.DataContext = this;
ControlList.DataContext = this;
ControlText.TextChanged += TextChanged;
ControlText.GotKeyboardFocus += KeyboardFocusChanged;
ControlText.LostKeyboardFocus += KeyboardFocusChanged;
ControlList.SelectionChanged += SelectionChanged;
ControlList.GotKeyboardFocus += KeyboardFocusChanged;
ControlList.LostKeyboardFocus += KeyboardFocusChanged;
IsKeyboardFocusWithinChanged += DDTextBox_IsKeyboardFocusWithinChanged;
}
private void TextChanged(object sender, TextChangedEventArgs e)
{ DItemsSource = ItemsSource.Cast<string>().ToList().FindAll(r => r.IndexOf(( (TextBox)sender ).Text, StringComparison.OrdinalIgnoreCase) >= 0); }
private void SelectionChanged(object sender, SelectionChangedEventArgs e)
{ Text = ( e.AddedItems.Count > 0 ) ? e.AddedItems[0].ToString() : string.Empty; ( (ListBox)sender ).Visibility = Visibility.Collapsed; }
private void KeyboardFocusChanged(object sender, KeyboardFocusChangedEventArgs e)
{
ControlList.Visibility = ( e.NewFocus == ControlList || e.NewFocus == ControlText ) ? Visibility.Visible : Visibility.Collapsed;
if ( e.OldFocus?.GetType() == typeof(ListBox) ) ( (ListBox)e.OldFocus ).SelectedIndex = -1;
}
private void DDTextBox_IsKeyboardFocusWithinChanged(object sender, DependencyPropertyChangedEventArgs e)
{
if ( (bool)e.OldValue == true && (bool)e.NewValue == false )
{ RaiseEvent(new RoutedEventArgs(UserControlLostFocusEvent, this)); }
}
private void ControlLostFocus(object sender, RoutedEventArgs e)
{ if ( !ControlList.IsFocused && !ControlText.IsFocused ) { ControlList.Visibility = Visibility.Collapsed; ControlList.SelectedIndex = -1; } }
public event RoutedEventHandler UserControlLostFocus
{
add { AddHandler(UserControlLostFocusEvent, value); }
remove { RemoveHandler(UserControlLostFocusEvent, value); }
}
public IEnumerable ItemsSource
{
private get { return (IEnumerable)GetValue(ItemsSourceProperty); }
set { SetValue(ItemsSourceProperty, value); SetValue(DItemsSourceProperty, value); }
}
/// <summary>
/// Dynamically generated ItemsSource based on Text property. Changes made to this may be lost. List changes should be made to the ItemsSource.
/// </summary>
public IEnumerable DItemsSource
{
private get { return (IEnumerable)GetValue(DItemsSourceProperty); }
set { SetValue(DItemsSourceProperty, value); }
}
public static DependencyProperty DItemsSourceProperty => dItemsSourceProperty;
public static DependencyProperty ItemsSourceProperty => itemsSourceProperty;
public static RoutedEvent UserControlLostFocusEvent => userControlLostFocusEvent;
private static readonly DependencyProperty itemsSourceProperty = DependencyProperty.Register("ItemsSource", typeof(IEnumerable), typeof(DDTextBox), new PropertyMetadata(new PropertyChangedCallback(OnItemsSourcePropertyChanged)));
private static readonly DependencyProperty dItemsSourceProperty = DependencyProperty.Register("DItemsSource", typeof(IEnumerable), typeof(DDTextBox), new PropertyMetadata(new PropertyChangedCallback(OnItemsSourcePropertyChanged)));
private static readonly RoutedEvent userControlLostFocusEvent = EventManager.RegisterRoutedEvent("UserControlLostFocus", RoutingStrategy.Bubble, typeof(RoutedEventHandler), typeof(DDTextBox));
private static void OnItemsSourcePropertyChanged(DependencyObject sender, DependencyPropertyChangedEventArgs e)
{ if ( sender is DDTextBox control ) control.OnItemsSourceChanged((IEnumerable)e.NewValue, (IEnumerable)e.OldValue); }
private void OnItemsSourceChanged(IEnumerable newValue, IEnumerable oldValue)
{
if ( oldValue is INotifyCollectionChanged oldValueINotifyCollectionChanged )
{ oldValueINotifyCollectionChanged.CollectionChanged -= new NotifyCollectionChangedEventHandler(NewValueINotifyCollectionChanged_CollectionChanged); }
if ( newValue is INotifyCollectionChanged newValueINotifyCollectionChanged )
{ newValueINotifyCollectionChanged.CollectionChanged += new NotifyCollectionChangedEventHandler(NewValueINotifyCollectionChanged_CollectionChanged); }
}
void NewValueINotifyCollectionChanged_CollectionChanged(object sender, NotifyCollectionChangedEventArgs e) { }
public event PropertyChangedEventHandler PropertyChanged;
public void OnPropertyChanged([CallerMemberName] string Name = "")
{ PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(Name)); }
}
}
Referenced in my main project and added to the main window:
<Window Name="Main" x:Class="POSystem.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:myCtrls="clr-namespace:UserControlsLibrary;assembly=UserControlsLibrary"
Title="Purchase Order" Height="850" Width="1100" Background="#FFD8D0A9">
<Grid Name="TheGrid" Focusable="True" MouseDown="ClearFocus_OnClick" Background="Transparent">
<myCtrls:DDTextBox x:Name="ItemsBox" Width="300" VerticalAlignment="Top" HorizontalAlignment="Left" Panel.ZIndex="1"/>
</Grid>
</Window>
At runtime everything shows up and works as it is supposed too, however, in the window designer of the main page it does not show anything other than an outline indicating that the control is there. This outline can range from a single line at the location (only way all the functionality works proper) or if I add a minimum or just straight height it shows an empty outline of the control. How do I get this to show the (supposed to be) visible at all times textbox within the user control in the main window designer?

Categories