|
Both. Your app should anticipate the user's intention by the parts they're accessing and start asynchronous loads into observable collections that get bound when a particular user control ("view") gets loaded.
And / or you need revised stored procs / data views / filtering.
"Before entering on an understanding, I have meditated for a long time, and have foreseen what might happen. It is not genius which reveals to me suddenly, secretly, what I have to say or to do in a circumstance unexpected by other people; it is reflection, it is meditation." - Napoleon I
|
|
|
|
|
I'm looking for a control that does the following.
When I do an action in my UI, I want to have a small window that slides in an out showing a small explanation text.
For example, I have a "copy" button that will put something on the clipboard.
I want to show a quick message that said "XYZ copied on the clipboard" the message will slide in and out of the main window.
I was looking at <popup> with an animation but I'm not sure it's what I want.
Or do you have a better alternative ?
Thanks.
CI/CD = Continuous Impediment/Continuous Despair
|
|
|
|
|
|
thanks, will have a look at it.
CI/CD = Continuous Impediment/Continuous Despair
|
|
|
|
|
it looks nice, even if it is a little bit "in your face".
Will experiment with look and feel.
Thanks again
CI/CD = Continuous Impediment/Continuous Despair
|
|
|
|
|
I have a button with a contextual menu attached to it, I want display the menu on the left click instead of the default right click.
I'm using a company wide "resource pack" that defines some style.
When I left click on the button to open the menu, the menu is drawn/rendered using the default windows style and the event/commands are not triggered.
When I right click on the button to open the menu, the menu is drawn/rendered using our styles and events/commands are working.
When I left click again the menu is drawn/rendered using our styles and event/commands are working
I'm not sure why the wrong menu is loaded once.
Any insights or things I might have missed ?
<Window.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="pack://application:,,,/MyCompany.Presentation;component/Themes/MyCompany.xaml" />
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>
</Window.Resources>
<!-- ... -->
<Button Content="Right-Click Me!" Click="ButtonBase_OnClick">
<Button.ContextMenu>
<ContextMenu x:Name="MyContextMenu">
<MenuItem Header="a" IsCheckable="True" Command="{Binding DoACommand}" IsChecked="{Binding IsAChecked, Mode=OneWay}"/>
<MenuItem Header="b" IsCheckable="True" Command="{Binding DoBCommand}" IsChecked="{Binding IsBChecked, Mode=OneWay}"/>
</ContextMenu>
</Button.ContextMenu>
</Button>
private void ButtonBase_OnClick(object sender, RoutedEventArgs e)
{
if (MyContextMenu.ContextMenu != null)
MyContextMenu.ContextMenu.IsOpen = true;
}
CI/CD = Continuous Impediment/Continuous Despair
|
|
|
|
|
The WPF ContextMenu doesn't inherit the DataContext of its parent element. You need to set that explicitly for the bindings to work:
<ContextMenu x:Name="MyContextMenu" DataContext="{Binding PlacementTarget, RelativeSource={RelativeSource Self}}"> As for the styles not being applied when you left-click, have you tried different sequences? Try two left-clicks, or a right-click followed by a left click, to see whether the styles are applied the second time the menu appears, or only applied after a right-click.
"These people looked deep within my soul and assigned me a number based on the order in which I joined."
- Homer
|
|
|
|
|
Adding the datacontext does not change anything.
The menu loads correctly the first when I right click on the button; after that it loads correctly on the left click.
It's not urgent for now, I'm prototyping a UI. , but slightly annoying.
Thanks.
CI/CD = Continuous Impediment/Continuous Despair
|
|
|
|
|
I converted a .Net Framework WPF app to .Net Core. I now have 1800+ compilation errors.
It seems like 99% of them are
The name 'InitializeComponent' does not exist in the current context
Since this is so widespread, I'm going to assume something in the conversion broke this. I've been Googling and trying different things but no help.
I tried removing the obj & bin folders but that didn't solve anything.
Anyone have any ideas on this?
If it's not broken, fix it until it is.
Everything makes sense in someone's mind.
Ya can't fix stupid.
|
|
|
|
|
Double-check that your project has the correct SDK: Sdk="Microsoft.NET.Sdk.WindowsDesktop"
Also double-check that in contains <UseWPF>true</UseWPF> within a <PropertyGroup> element.
"These people looked deep within my soul and assigned me a number based on the order in which I joined."
- Homer
|
|
|
|
|
I opened the project file in Notepad++.
The first line of the csproj file is
<Project Sdk="Microsoft.NET.Sdk">
The second line exists in a PropertyGroup
I tried replacing the SDK and recompiled. Same result. 1800+ errors
Thanks
If it's not broken, fix it until it is.
Everything makes sense in someone's mind.
Ya can't fix stupid.
|
|
|
|
|
I've made a bit more progress on this. The app has multiple configurations. When the configuration is changed, a bar appears at the top that says
Current solution contains incorrect configurations mappings. It may cause projects to not work correctly. Open the Configuration Manager to fix them
None of the code wrapped in an #if / #endif sections are active, so this leads me to believe there's a config issue. Since the project file was converted from .Net Framework to .Net Core, I'm a bit unsure on what to look for.
Any thoughts on this?
Thanks!
If it's not broken, fix it until it is.
Everything makes sense in someone's mind.
Ya can't fix stupid.
|
|
|
|
|
It looks like that's related to "conditions" in the csproj referring to configuration profiles that don't exist in the solution. Look for things like:
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration> and check that the configuration value matches an existing build configuration for your solution:
Understand build configurations - Visual Studio (Windows) | Microsoft Learn[^]
"These people looked deep within my soul and assigned me a number based on the order in which I joined."
- Homer
|
|
|
|
|
Im building a Ticker User Control and my dependency property's that directly bind to the XAML which works great, but I have some dependency property's that drive the Beating Internal Class which controls the motion of the three bars.
When I change these in the viewmodel they have no affect on the Internal Class Property's so I cant change the speed or starting length and so on.
I though if I passed in the Code behind class into the Beating internal class I could do it this way, but i almost need an onPropertychanged event to force the update.
thanks
Madaxe
XAML User Control
<UserControl x:Class="DES.CATIAV6.ClearanceContactAndClashManager.UI.Controls.WaitTicker_Control"
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:DES.CATIAV6.ClearanceContactAndClashManager.UI.Controls"
mc:Ignorable="d"
Background="Transparent"
Height="70" Width="60"
Name="WaitTickerControl">
<Grid Name="WaitTickerMainGrid" Visibility="{Binding Path=ControlHideShow,ElementName=WaitTickerControl, FallbackValue=Hidden}">
<Border Name="Pulse1"
CornerRadius="{Binding Path=ControlCornerRadius1,ElementName=WaitTickerControl,FallbackValue=10}"
Height="{Binding Path=PulseHeight1,ElementName=WaitTickerControl,FallbackValue=50}"
Width="{Binding Path=PulseWidth1,ElementName=WaitTickerControl,FallbackValue=10}"
Margin="10,10,0,0"
Background="{Binding Path=ControlBackground1,ElementName=WaitTickerControl,FallbackValue=#4287f5}"
HorizontalAlignment="Left" VerticalAlignment="Top"/>
<Border Name="Pulse2"
CornerRadius="{Binding Path=ControlCornerRadius2,ElementName=WaitTickerControl,FallbackValue=10}"
Height="{Binding Path=PulseHeight2,ElementName=WaitTickerControl,FallbackValue=50}"
Width="{Binding Path=PulseWidth2,ElementName=WaitTickerControl,FallbackValue=10}"
Margin="25,10,0,0"
Background="{Binding Path=ControlBackground2,ElementName=WaitTickerControl,FallbackValue=#4287f5}"
HorizontalAlignment="Left" VerticalAlignment="Top"/>
<Border Name="Pulse3"
CornerRadius="{Binding Path=ControlCornerRadius3,ElementName=WaitTickerControl,FallbackValue=10}"
Height="{Binding Path=PulseHeight3,ElementName=WaitTickerControl,FallbackValue=50}"
Width="{Binding Path=PulseWidth3,ElementName=WaitTickerControl,FallbackValue=10}"
Margin="40,10,0,0"
Background="{Binding Path=ControlBackground3,ElementName=WaitTickerControl,FallbackValue=#4287f5}"
HorizontalAlignment="Left" VerticalAlignment="Top"/>
</Grid>
</UserControl>
C# Code Behind
public partial class WaitTicker_Control : UserControl, INotifyPropertyChanged
{
#region "INotifyPropertyChanged"
public event PropertyChangedEventHandler? PropertyChanged;
protected void OnPropertyChanged([CallerMemberName] string? propertyName = null)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
private Beating? _Timer1 = null;
private Beating? _Timer2 = null;
private Beating? _Timer3 = null;
public int PulseCurrentValue1
{
get { return (int)GetValue(PulseCurrentValue1Property); }
set { SetValue(PulseCurrentValue1Property, value); }
}
public static readonly DependencyProperty PulseCurrentValue1Property =
DependencyProperty.Register("PulseCurrentValue1", typeof(int), typeof(WaitTicker_Control),
new PropertyMetadata(5));
public int PulseCurrentValue2
{
get { return (int)GetValue(PulseCurrentValue2Property); }
set { SetValue(PulseCurrentValue2Property, value); }
}
public static readonly DependencyProperty PulseCurrentValue2Property =
DependencyProperty.Register("PulseCurrentValue2", typeof(int), typeof(WaitTicker_Control),
new PropertyMetadata(20));
public int PulseCurrentValue3
{
get { return (int)GetValue(PulseCurrentValue3Property); }
set { SetValue(PulseCurrentValue3Property, value); }
}
public static readonly DependencyProperty PulseCurrentValue3Property =
DependencyProperty.Register("PulseCurrentValue3", typeof(int), typeof(WaitTicker_Control),
new PropertyMetadata(40));
public int PulseMaxValue
{
get { return (int)GetValue(PulseMaxValueProperty); }
set { SetValue(PulseMaxValueProperty, value); }
}
public static readonly DependencyProperty PulseMaxValueProperty =
DependencyProperty.Register("PulseMaxValue", typeof(int), typeof(WaitTicker_Control),
new PropertyMetadata(50));
public int PulseMinValue
{
get { return (int)GetValue(PulseMinValueProperty); }
set { SetValue(PulseMinValueProperty, value); }
}
public static readonly DependencyProperty PulseMinValueProperty =
DependencyProperty.Register("PulseMinValue", typeof(int), typeof(WaitTicker_Control),
new PropertyMetadata(10));
public int PulseIncrementValue
{
get { return (int)GetValue(PulseIncrementValueProperty); }
set { SetValue(PulseIncrementValueProperty, value); }
}
public static readonly DependencyProperty PulseIncrementValueProperty =
DependencyProperty.Register("PulseIncrementValue", typeof(int), typeof(WaitTicker_Control),
new PropertyMetadata(1));
public double PulseSpeedValue
{
get { return (double)GetValue(PulseSpeedValueProperty); }
set { SetValue(PulseSpeedValueProperty, value); }
}
public static readonly DependencyProperty PulseSpeedValueProperty =
DependencyProperty.Register("PulseSpeedValue", typeof(double), typeof(WaitTicker_Control),
new PropertyMetadata(0.01));
#endregion
public WaitTicker_Control()
{
InitializeComponent();
_Timer1 = new Beating(Pulse1, this, PulseCurrentValue1, "Pulse1");
_Timer2 = new Beating(Pulse2, this, PulseCurrentValue2, "Pulse2");
_Timer3 = new Beating(Pulse3, this, PulseCurrentValue3, "Pulse3");
}
}
internal Class Code Behind
internal class Beating
{
private static Timer? _BeatingTimer=null;
private Dispatcher? _Dispatcher=null;
private WaitTicker_Control _waitTicker_Control;
private Border? _pulse { get; set; } = null;
private bool _Direction = false;
public string BeatName { get; set; } = string.Empty;
public int InitialValue { get; set; } = 50;
public int Increment { get; set; } = 1;
public int MinValue { get; set; } = 0;
public int MaxValue { get; set; } = 100;
public Beating(
Border pulse,
WaitTicker_Control waitTicker_Control,
int initialValue,
string iBeatName)
{
_waitTicker_Control = waitTicker_Control;
_pulse = pulse;
MinValue = waitTicker_Control.PulseMinValue;
MaxValue = waitTicker_Control.PulseMaxValue;
InitialValue = initialValue;
Increment = waitTicker_Control.PulseIncrementValue;
BeatName = iBeatName;
_Dispatcher = Dispatcher.CurrentDispatcher;
Beating._BeatingTimer = new Timer();
Beating._BeatingTimer.Interval = waitTicker_Control.PulseSpeedValue;
Beating._BeatingTimer.Elapsed += OnTimedEvent;
Beating._BeatingTimer.AutoReset = true;
Beating._BeatingTimer.Enabled = true;
}
public void StartTimer()
{
Beating._BeatingTimer?.Start();
}
public void StopTimer()
{
Beating._BeatingTimer?.Stop();
}
private void OnTimedEvent(Object source, ElapsedEventArgs e)
{
try
{
if (this._Direction == false)
{
this.InitialValue = this.InitialValue - this.Increment;
if (this.InitialValue < this.MinValue)
this._Direction = true;
}
else
{
this.InitialValue = this.InitialValue + this.Increment;
if (this.InitialValue > this.MaxValue)
this._Direction = false;
}
if (this._pulse != null)
{
this._Dispatcher?.Invoke(new Action(() => { this._pulse.Height = this.InitialValue; }));
}
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
}
}
}
|
|
|
|
|
Marc Jeeves wrote: public partial class WaitTicker_Control : UserControl, INotifyPropertyChanged
A DependencyObject such as a UserControl doesn't need to implement INotifyPropertyChanged . The DependencyProperty already raises the necessary events when the value changes.
You're passing in the current value of a DependencyProperty to the Beating class. At that point, there is no connection between the int in the Beating class and the DependencyProperty .
The simplest option is probably to reverse the connection, and use binding to move the values around when they change:
internal sealed class Beating : INotifyPropertyChanged
{
private readonly Timer? _timer;
private int _value;
private bool _direction;
public int Value
{
get { return _value; }
set
{
if (value != _value)
{
_value = value;
OnPropertyChanged();
}
}
}
public int Increment { get; set; }
public int MinValue { get; set; }
public int MaxValue { get; set; }
public string BeatName { get; }
public double Speed
{
get { return _timer.Interval; }
set { _timer.Interval = value; }
}
public event PropertyChangedEventHandler? PropertyChanged;
private void OnPropertyChanged([CallerMemberName] string? propertyName = null)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
public Beating(int initialValue, int increment, int minValue, int maxValue, string beatName, double speed)
{
_value = initialValue;
Increment = increment;
MinValue = minValue;
MaxValue = maxValue;
BeatName = beatName;
_timer = new Timer
{
Interval = speed,
AutoReset = true,
Enabled = true,
};
_timer.Elapsed += OnTimedEvent;
}
public void StartTimer()
{
_timer.Start();
}
public void StopTimer()
{
_timer.Stop();
}
private void OnTimedEvent(Object source, ElapsedEventArgs e)
{
if (!_direction)
{
Value -= Increment;
if (Value < MinValue)
_direction = true;
}
else
{
Value += Increment;
if (Value > MaxValue)
_direction = false;
}
}
}
public partial class WaitTicker_Control : UserControl
{
private Beating _timer1;
private Beating _timer2;
private Beating _timer3;
private Beating CreateBeating(string beatName, DependencyProperty valueProperty, Border pulse)
{
Beating result = new Beating((int)GetValue(valueProperty), PulseIncrementValue, PulseMinValue, PulseMaxValue, beatName, PulseSpeedValue);
SetBinding(PulseIncrementValueProperty, new Binding(nameof(Beating.Increment)) { Source = result, Mode = BindingMode.OneWayToSource });
SetBinding(PulseMinValueProperty, new Binding(nameof(Beating.MinValue)) { Source = result, Mode = BindingMode.OneWayToSource });
SetBinding(PulseMaxValueProperty, new Binding(nameof(Beating.MaxValue)) { Source = result, Mode = BindingMode.OneWayToSource });
SetBinding(PulseSpeedValueProperty, new Binding(nameof(Beating.Speed)) { Source = result, Mode = BindingMode.OneWayToSource });
pulse.SetBinding(FrameworkElement.HeightProperty, new Binding(nameof(Beating.Value)) { Source = result, Mode = BindingMode.OneWay });
return result;
}
public WaitTicker_Control()
{
InitializeComponent();
_timer1 = CreateBeating("Pulse1", PulseCurrentValue1Property, Pulse1);
_timer2 = CreateBeating("Pulse2", PulseCurrentValue2Property, Pulse2);
_timer3 = CreateBeating("Pulse3", PulseCurrentValue3Property, Pulse3);
}
"These people looked deep within my soul and assigned me a number based on the order in which I joined."
- Homer
|
|
|
|
|
Thanks I will give it a try, and post the full example once completed for others.
|
|
|
|
|
It would appear that you have two accounts. Please close the one you do not need.
|
|
|
|
|
So I have three last issues, thanks for all the help
1) if I use the usercontrol name "Name="WaitTickerCustomControl" then the Custom Control disappears in the Main Window odd.
2) The directly Bound dependency property are bound but nothing updates
3) The Indirectly Bound property's only affect the third ticker odd...
Thanks for the help im learning alot.
Madaxe
XAML Custom Control
<pre><UserControl x:Class="Testing.CustomControls.WaitTicker_CustomControl"
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:Testing.CustomControls"
mc:Ignorable="d"
d:DesignHeight="70" d:DesignWidth="60"
Name="WaitTickerCustomControl">
<Grid Name="WaitTickerMainGrid" Visibility="{Binding Path=ControlHideShow,ElementName=WaitTickerCustomControl, FallbackValue=Visible}">
<Border Name="Pulse1"
CornerRadius="{Binding Path=ControlCornerRadius1,ElementName=WaitTickerCustomControl,FallbackValue=10}"
Height="{Binding Path=PulseHeight1,ElementName=WaitTickerCustomControl,FallbackValue=50}"
Width="{Binding Path=PulseWidth1,ElementName=WaitTickerCustomControl,FallbackValue=10}"
Margin="10,10,0,0"
Background="{Binding Path=ControlBackground1,ElementName=WaitTickerCustomControl,FallbackValue=#4287f5}"
HorizontalAlignment="Left" VerticalAlignment="Top"/>
<Border Name="Pulse2"
CornerRadius="{Binding Path=ControlCornerRadius2,ElementName=WaitTickerCustomControl,FallbackValue=10}"
Height="{Binding Path=PulseHeight2,ElementName=WaitTickerCustomControl,FallbackValue=50}"
Width="{Binding Path=PulseWidth2,ElementName=WaitTickerCustomControl,FallbackValue=10}"
Margin="25,10,0,0"
Background="{Binding Path=ControlBackground2,ElementName=WaitTickerCustomControl,FallbackValue=#4287f5}"
HorizontalAlignment="Left" VerticalAlignment="Top"/>
<Border Name="Pulse3"
CornerRadius="{Binding Path=ControlCornerRadius3,ElementName=WaitTickerCustomControl,FallbackValue=10}"
Height="{Binding Path=PulseHeight3,ElementName=WaitTickerCustomControl,FallbackValue=50}"
Width="{Binding Path=PulseWidth3,ElementName=WaitTickerCustomControl,FallbackValue=10}"
Margin="40,10,0,0"
Background="{Binding Path=ControlBackground3,ElementName=WaitTickerCustomControl,FallbackValue=#4287f5}"
HorizontalAlignment="Left" VerticalAlignment="Top"/>
</Grid>
</UserControl>
XAML Code Behind
public partial class WaitTicker_CustomControl : UserControl, INotifyPropertyChanged
{
public event PropertyChangedEventHandler? PropertyChanged;
protected void OnPropertyChanged([CallerMemberName] string? propertyName = null)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
public Visibility ControlHideShow
{
get { return (Visibility)GetValue(ControlHideShowProperty); }
set { SetValue(ControlHideShowProperty, value); }
}
public static readonly DependencyProperty ControlHideShowProperty =
DependencyProperty.Register("ControlHideShow", typeof(Visibility),
typeof(WaitTicker_CustomControl),
new PropertyMetadata(Visibility.Hidden));
public int ControlCornerRadius1
{
get { return (int)GetValue(ControlCornerRadius1Property); }
set { SetValue(ControlCornerRadius1Property, value); }
}
public static readonly DependencyProperty ControlCornerRadius1Property =
DependencyProperty.Register("ControlCornerRadius1", typeof(int),
typeof(WaitTicker_CustomControl),
new PropertyMetadata(10));
public int ControlCornerRadius2
{
get { return (int)GetValue(ControlCornerRadius2Property); }
set { SetValue(ControlCornerRadius2Property, value); }
}
public static readonly DependencyProperty ControlCornerRadius2Property =
DependencyProperty.Register("ControlCornerRadius2", typeof(int),
typeof(WaitTicker_CustomControl),
new PropertyMetadata(10));
public int ControlCornerRadius3
{
get { return (int)GetValue(ControlCornerRadius3Property); }
set { SetValue(ControlCornerRadius3Property, value); }
}
public static readonly DependencyProperty ControlCornerRadius3Property =
DependencyProperty.Register("ControlCornerRadius3", typeof(int),
typeof(WaitTicker_CustomControl),
new PropertyMetadata(10));
public int PulseHeight1
{
get { return (int)GetValue(PulseHeight1Property); }
set { SetValue(PulseHeight1Property, value); }
}
public static readonly DependencyProperty PulseHeight1Property =
DependencyProperty.Register("PulseHeight1", typeof(int),
typeof(WaitTicker_CustomControl),
new PropertyMetadata(1));
public int PulseHeight2
{
get { return (int)GetValue(PulseHeight2Property); }
set { SetValue(PulseHeight2Property, value); }
}
public static readonly DependencyProperty PulseHeight2Property =
DependencyProperty.Register("PulseHeight2", typeof(int),
typeof(WaitTicker_CustomControl),
new PropertyMetadata(25));
public int PulseHeight3
{
get { return (int)GetValue(PulseHeight3Property); }
set { SetValue(PulseHeight3Property, value); }
}
public static readonly DependencyProperty PulseHeight3Property =
DependencyProperty.Register("PulseHeight3", typeof(int),
typeof(WaitTicker_CustomControl),
new PropertyMetadata(50));
public int PulseWidth1
{
get { return (int)GetValue(PulseWidth1Property); }
set { SetValue(PulseWidth1Property, value); }
}
public static readonly DependencyProperty PulseWidth1Property =
DependencyProperty.Register("PulseWidth1", typeof(int),
typeof(WaitTicker_CustomControl),
new PropertyMetadata(20));
public int PulseWidth2
{
get { return (int)GetValue(PulseWidth2Property); }
set { SetValue(PulseWidth2Property, value); }
}
public static readonly DependencyProperty PulseWidth2Property =
DependencyProperty.Register("PulseWidth2", typeof(int),
typeof(WaitTicker_CustomControl),
new PropertyMetadata(20));
public int PulseWidth3
{
get { return (int)GetValue(PulseWidth3Property); }
set { SetValue(PulseWidth3Property, value); }
}
public static readonly DependencyProperty PulseWidth3Property =
DependencyProperty.Register("PulseWidth3", typeof(int),
typeof(WaitTicker_CustomControl),
new PropertyMetadata(0));
public Brush ControlBackground1
{
get { return (Brush)GetValue(ControlBackground1Property); }
set { SetValue(ControlBackground1Property, value); }
}
public static readonly DependencyProperty ControlBackground1Property =
DependencyProperty.Register("ControlBackground1", typeof(Brush),
typeof(WaitTicker_CustomControl),
new PropertyMetadata(Brushes.Blue));
public Brush ControlBackground2
{
get { return (Brush)GetValue(ControlBackground2Property); }
set { SetValue(ControlBackground2Property, value); }
}
public static readonly DependencyProperty ControlBackground2Property =
DependencyProperty.Register("ControlBackground2", typeof(Brush),
typeof(WaitTicker_CustomControl),
new PropertyMetadata(Brushes.Blue));
public Brush ControlBackground3
{
get { return (Brush)GetValue(ControlBackground3Property); }
set { SetValue(ControlBackground3Property, value); }
}
public static readonly DependencyProperty ControlBackground3Property =
DependencyProperty.Register("ControlBackground3", typeof(Brush),
typeof(WaitTicker_CustomControl),
new PropertyMetadata(Brushes.Blue));
private Beating _timer1;
private Beating _timer2;
private Beating _timer3;
public int PulseIncrementValue
{
get { return (int)GetValue(PulseIncrementValueProperty); }
set { SetValue(PulseIncrementValueProperty, value); }
}
public static readonly DependencyProperty PulseIncrementValueProperty =
DependencyProperty.Register("PulseIncrementValue", typeof(int),
typeof(WaitTicker_CustomControl),
new PropertyMetadata(1));
public int PulseMaxValue
{
get { return (int)GetValue(PulseMaxValueProperty); }
set { SetValue(PulseMaxValueProperty, value); }
}
public static readonly DependencyProperty PulseMaxValueProperty =
DependencyProperty.Register("PulseMaxValue", typeof(int),
typeof(WaitTicker_CustomControl),
new PropertyMetadata(50));
public int PulseMinValue
{
get { return (int)GetValue(PulseMinValueProperty); }
set { SetValue(PulseMinValueProperty, value); }
}
public static readonly DependencyProperty PulseMinValueProperty =
DependencyProperty.Register("PulseMinValue", typeof(int),
typeof(WaitTicker_CustomControl),
new PropertyMetadata(10));
public double PulseSpeedValue
{
get { return (double)GetValue(PulseSpeedValueProperty); }
set { SetValue(PulseSpeedValueProperty, value); }
}
public static readonly DependencyProperty PulseSpeedValueProperty =
DependencyProperty.Register("PulseSpeedValue", typeof(double),
typeof(WaitTicker_CustomControl),
new PropertyMetadata(0.01));
public int PulseCurrentValue1
{
get { return (int)GetValue(PulseCurrentValue1Property); }
set { SetValue(PulseCurrentValue1Property, value); }
}
public static readonly DependencyProperty PulseCurrentValue1Property =
DependencyProperty.Register("PulseCurrentValue1", typeof(int),
typeof(WaitTicker_CustomControl),
new PropertyMetadata(5));
public int PulseCurrentValue2
{
get { return (int)GetValue(PulseCurrentValue2Property); }
set { SetValue(PulseCurrentValue2Property, value); }
}
public static readonly DependencyProperty PulseCurrentValue2Property =
DependencyProperty.Register("PulseCurrentValue2", typeof(int),
typeof(WaitTicker_CustomControl),
new PropertyMetadata(20));
public int PulseCurrentValue3
{
get { return (int)GetValue(PulseCurrentValue3Property); }
set { SetValue(PulseCurrentValue3Property, value); }
}
public static readonly DependencyProperty PulseCurrentValue3Property =
DependencyProperty.Register("PulseCurrentValue3", typeof(int),
typeof(WaitTicker_CustomControl),
new PropertyMetadata(40));
private Beating CreateBeating(string beatName, DependencyProperty valueProperty, Border pulse)
{
Beating result = new Beating((int)GetValue(valueProperty), PulseIncrementValue, PulseMinValue, PulseMaxValue, beatName, PulseSpeedValue);
SetBinding(PulseIncrementValueProperty, new Binding(nameof(Beating.Increment)) { Source = result, Mode = BindingMode.OneWayToSource });
SetBinding(PulseMinValueProperty, new Binding(nameof(Beating.MinValue)) { Source = result, Mode = BindingMode.OneWayToSource });
SetBinding(PulseMaxValueProperty, new Binding(nameof(Beating.MaxValue)) { Source = result, Mode = BindingMode.OneWayToSource });
SetBinding(PulseSpeedValueProperty, new Binding(nameof(Beating.Speed)) { Source = result, Mode = BindingMode.OneWayToSource });
pulse.SetBinding(FrameworkElement.HeightProperty, new Binding(nameof(Beating.Value)) { Source = result, Mode = BindingMode.OneWay });
return result;
}
public WaitTicker_CustomControl()
{
InitializeComponent();
_timer1 = CreateBeating("Pulse1", PulseCurrentValue1Property, Pulse1);
_timer2 = CreateBeating("Pulse2", PulseCurrentValue2Property, Pulse2);
_timer3 = CreateBeating("Pulse3", PulseCurrentValue3Property, Pulse3);
}
}
internal sealed class Beating : INotifyPropertyChanged
{
private readonly Timer? _timer;
private int _value;
private bool _direction;
public int Value
{
get { return _value; }
set
{
if (value != _value)
{
_value = value;
OnPropertyChanged();
}
}
}
public int Increment { get; set; }
public int MinValue { get; set; }
public int MaxValue { get; set; }
public string BeatName { get; }
public double Speed
{
get { return _timer.Interval; }
set { _timer.Interval = value; }
}
public event PropertyChangedEventHandler? PropertyChanged;
private void OnPropertyChanged([CallerMemberName] string? propertyName = null)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
public Beating(int initialValue, int increment, int minValue, int maxValue, string beatName, double speed)
{
_value = initialValue;
Increment = increment;
MinValue = minValue;
MaxValue = maxValue;
BeatName = beatName;
_timer = new Timer
{
Interval = speed,
AutoReset = true,
Enabled = true,
};
_timer.Elapsed += OnTimedEvent;
}
public void StartTimer()
{
_timer.Start();
}
public void StopTimer()
{
_timer.Stop();
}
private void OnTimedEvent(Object source, ElapsedEventArgs e)
{
if (!_direction)
{
Value -= Increment;
if (Value < MinValue)
_direction = true;
}
else
{
Value += Increment;
if (Value > MaxValue)
_direction = false;
}
}
}
Custom Control Implementation
<Window x:Class="Testing.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:Testing" xmlns:customcontrols="clr-namespace:Testing.CustomControls"
mc:Ignorable="d"
Title="MainWindow" Height="450" Width="800">
<Grid>
<customcontrols:WaitTicker_CustomControl
Height="100" Width="100"
VerticalAlignment="Top" HorizontalAlignment="Left"
Margin="10 10 0 0"
PulseMaxValue="100"
PulseMinValue="5"
PulseHeight1="100"
PulseHeight2="100"
PulseHeight3="100"
PulseSpeedValue="50"
ControlCornerRadius1="5"
ControlCornerRadius2="5"
ControlCornerRadius3="5"
ControlBackground1="Aquamarine"
ControlBackground2="Yellow"
ControlBackground3="Orange"/>
</Grid>
</Window>
modified 3-Sep-22 18:15pm.
|
|
|
|
|
ElementName=WaitTickerCustomControl
A pointless assignment. Which is addressed by a simple
this.DataContext = this; in the constructor. (Which may be required in any case).
All your "dependency properties", on first glance, look like a reach that could have been defaulted in code behind; complimented with an "options" flyout / popup.
"Before entering on an understanding, I have meditated for a long time, and have foreseen what might happen. It is not genius which reveals to me suddenly, secretly, what I have to say or to do in a circumstance unexpected by other people; it is reflection, it is meditation." - Napoleon I
|
|
|
|
|
Gerry Schmitz wrote: this.DataContext = this;
Which will almost certainly bring you back to the original problem[^].
"These people looked deep within my soul and assigned me a number based on the order in which I joined."
- Homer
|
|
|
|
|
Each control has a DataContext. You can let them default to a "higher up", or set them each explicitly. Setting a DataContext is rarely an issue; omitting them is. The excess of pointless XAML and dependency properties is obfuscating the problem. That was my (indirect) point.
"Before entering on an understanding, I have meditated for a long time, and have foreseen what might happen. It is not genius which reveals to me suddenly, secretly, what I have to say or to do in a circumstance unexpected by other people; it is reflection, it is meditation." - Napoleon I
|
|
|
|
|
So how would you guys build this custom control?
|
|
|
|
|
You're actually creating a user control; and not a "custom control".
The "simplest" way to create a user control is to add properties {get;set;} to the UC in the .cs; bind the controls in the .xaml to the properties in the .cs; and implement INotifyPropertyChanged (which for a "few" controls, can be issued with "no contol name" without any hit on performance). The DataContext of the UC is the UC; i.e. "this".
Any time there is new data, you load the properties and call "property changed" which updates the UI. If it's a two-way UI, data moves to the properties and events on the controls get invoked (e.g. text changed).
That's the pattern, and most everything else has a "smell".
Anything else that happens is a function of what events the user control wants to "surface" (e.g. a request queued to an observable collection or file watcher).
"Before entering on an understanding, I have meditated for a long time, and have foreseen what might happen. It is not genius which reveals to me suddenly, secretly, what I have to say or to do in a circumstance unexpected by other people; it is reflection, it is meditation." - Napoleon I
|
|
|
|
|
Within my View Model i have a property and backer to bind to the ControlHideShow, I don't get a bind error but if I change the default value in the View Model nothing happens. If I don't bind in the Implementation XAML and set Visible or Hidden it works so why can I not bind to the ViewModel
thanks
Madaxe
Public interface ViewModel
{
Visibility ControlHideShow { get; set; }
}
public class MainPageViewModel : ViewModelBase, IMainPageViewModel
{
private Visibility _controlHideShow = Visibility.Visible;
public Visibility ControlHideShow
{
get => _controlHideShow;
set{ _controlHideShow = value; OnPropertyChanged(nameof(ControlHideShow)); }
}
}
Implementation XML
<controls:WaitTicker_Control
x:Name="WaitCursor"
Width="60" Height="30"
Grid.Row="4" Grid.Column="1"
HorizontalAlignment="Center"
VerticalAlignment="Center"
Margin="100 0 0 0"
ControlBackground1="#FFA5CD3C"
ControlBackground2="#FF208D2F"
ControlBackground3="#FF206A8D"
ControlCornerRadius1="2"
ControlCornerRadius2="2"
ControlCornerRadius3="2"
PulseHeight1="25" PulseHeight2="25" PulseHeight3="25"
PulseWidth1="5" PulseWidth2="5" PulseWidth3="5"
PulseMaxValue="50" PulseMinValue="5"
PulseSpeedValue="0.0001"
PulseIncrementValue="1"
PulseCurrentValue1="1" PulseCurrentValue2="25" PulseCurrentValue3="50"
ControlHideShow="{Binding ControlHideShow}"/>
Custom Control XAML
<UserControl x:Class="DES.CATIAV6.ClearanceContactAndClashManager.UI.Controls.WaitTicker_Control"
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:DES.CATIAV6.ClearanceContactAndClashManager.UI.Controls"
mc:Ignorable="d"
DataContext="{Binding RelativeSource={RelativeSource Self}}"
Background="Transparent"
Height="70" Width="60"
Name="WaitTickerControl">
<Grid Name="WaitTickerMainGrid" Visibility="{Binding Path=ControlHideShow,ElementName=WaitTickerControl, FallbackValue=Hidden}">
</Grid>
</UserControl>
Custom Control Code Behind
public partial class WaitTicker_Control : UserControl, INotifyPropertyChanged
{
public event PropertyChangedEventHandler? PropertyChanged;
protected void OnPropertyChanged([CallerMemberName] string? propertyName = null)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
public Visibility ControlHideShow
{
get { return (Visibility)GetValue(ControlHideShowProperty); }
set { SetValue(ControlHideShowProperty, value); }
}
public static readonly DependencyProperty ControlHideShowProperty =
DependencyProperty.Register("ControlHideShow", typeof(Visibility), typeof(WaitTicker_Control),
new PropertyMetadata(Visibility.Hidden));
|
|
|
|
|
I suspect it's because you've set the DataContext on the <UserControl> element. That means the <controls:WaitTickerControl ... ControlHideShow="{Binding ControlHideShow}" /> is binding the user control's property to itself, rather than the property from the inherited viewmodel.
Try removing the DataContext assignment - you've specified the ElementName in your binding, so you shouldn't need it.
<UserControl
x:Class="DES.CATIAV6.ClearanceContactAndClashManager.UI.Controls.WaitTicker_Control"
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:DES.CATIAV6.ClearanceContactAndClashManager.UI.Controls"
mc:Ignorable="d"
Background="Transparent"
Height="70" Width="60"
Name="WaitTickerControl"
>
<Grid Name="WaitTickerMainGrid" Visibility="{Binding Path=ControlHideShow, ElementName=WaitTickerControl, FallbackValue=Hidden}">
...
</Grid>
</UserControl> If that doesn't work, try setting the DataContext on the Grid instead of the UserControl .
"These people looked deep within my soul and assigned me a number based on the order in which I joined."
- Homer
|
|
|
|
|