|
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
|
|
|
|
|
Spot on, sometimes its the wood for the trees.
thanks a bunch
Madaxe
|
|
|
|
|
I searched the Internet and realized that there are different frameworks for the MVVM pattern used in WPF applications. One of them which is mostly used is MVVM Light but unfortunately, its development has ceased. I want to know what MVVM framework is mostly used and if there are adequate tutorials on the Internet for it.
|
|
|
|
|
It's hard to say which framework is the most common because stats like this aren't readily available. If you are just looking for a supported framework then Microsoft has a framework available as part of the community toolkit; it's well documented[^].
|
|
|
|
|
|
When doing Windows, I'll take MS first over the alternatives.
Quote: Prism 8 is a fully open source version of the Prism guidance originally produced by Microsoft patterns & practices.
Introduction to Prism | Prism
"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
|
|
|
|
|
Prism isn't Microsoft offering. It's maintained by Brian Lagunas and Dan Siegel. Both are MVPs, but work for other companies.
|
|
|
|
|
So, the fact that someone else now maintains it negates my opinion even though Microsoft originated it? Run with that.
"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
|
|
|
|
|
It has been so long away from the P&P camp that Microsoft's influence on it has long been expunged. The simple fact is, Microsoft has their own MVVM offering which has nothing to do with Prism. Your statement implied that Prism was a Microsoft offering and it hasn't been for a long time so if you are pushing someone to Microsoft's offering, at least make sure it is Microsoft that is offering it.
|
|
|
|
|
I have the following code in Code-Behind section of my WPF MVVM:
public EquipmentIdentity()
{
InitializeComponent();
EquipmentIdentityViewModel eivm = new EquipmentIdentityViewModel();
DataContext = eivm;
dataPager.OnDemandLoading += dataPager_OnDemandLoading;
}
private void dataPager_OnDemandLoading(object sender, Syncfusion.UI.Xaml.Controls.DataPager.OnDemandLoadingEventArgs args)
{
}
How can I remove this event handling from Code-Behind and take it to the ViewModel?
When I use dataPager.OnDemandLoading += dataPager_OnDemandLoading; in ViewModel it shows this error:
Quote: System.NullReferenceException: 'Object reference not set to an instance of an object.'
|
|
|
|
|
View models are about "data"; not "behavior".
mvc - Should MVVM models have behaviour? - Software Engineering Stack Exchange
"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
modified 17-Jul-22 12:22pm.
|
|
|
|
|
Hello everyone , I need your help , how to get dicom tags with wpf and openFileDialog
|
|
|
|
|
Reading DICOM file tags has nothing to do with WPF or the OpenFile dialog. WPF is a presentation (UI) framework, and an OpenFile dialog just gets a filepath from the user.
Reading the tag data is just straight up reading a file. There's plenty of info on the web on it. You just have to search for "C# read DICOM tags[^]" and start reading.
|
|
|
|
|
Just starting out in learning VS, C# and Xaml.
I am much older than most on here...I am betting anyway.
EE-PE that has folded a 20+ year Consulting Engineering business and trying to see if somehow I can do something in programming. I have struggled through and have a desktop app completed but have NO idea what is next.
Do a need to get a business certificate of some type so the app can load on others computers ?
Do I search out companies that market third party development ?
Do I partner with another developer to handle the marketing aspect ?
First choice of mine would be to find a Cleveland Ohio developer I could actually talk with, but have had zero success in this path.
modified 7-Jul-22 21:01pm.
|
|
|
|
|
Or you can put it in the Microsoft store.
Publish traditional desktop apps through Microsoft Store | Microsoft Developer
"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
|
|
|
|
|
Thank you for taking the time to respond.
Quickly looking over the link brings up even more questions.
Appears my weak general knowledge will keep this just a hobby.
modified 7-Jul-22 21:01pm.
|
|
|
|
|
I am creating a Custom Control and in the control template I have a TreeView class in it.
<Style TargetType="{x:Type local:MyControl}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type local:MyControl}">
<Border Background="{TemplateBinding Background}"
BorderBrush="{TemplateBinding BorderBrush}"
BorderThickness="{TemplateBinding BorderThickness}">
<TreeView ItemsSource="{Binding TreeDataItems, RelativeSource={RelativeSource TemplatedParent}}">
<TreeView.Resources>
<HierarchicalDataTemplate DataType="{x:Type local:TreeItem}" ItemsSource="{Binding Children}">
<TextBlock Text="{Binding Path=Caption}" />
</HierarchicalDataTemplate>
</TreeView.Resources>
<i:Interaction.Triggers>
<i:EventTrigger EventName="TreeViewItem.Expanded">
<i:InvokeCommandAction Command="{Binding TreeItemExpandedCommand, RelativeSource={RelativeSource TemplatedParent}}"
CommandParameter="{Binding}">
</i:InvokeCommandAction>
</i:EventTrigger>
</i:Interaction.Triggers>
</TreeView>
</Border>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
In the code behind I have
private ICommand _TreeItemExpandedCommand;
public ICommand TreeItemExpandedCommand
{
get
{
if (_TreeItemExpandedCommand == null)
_TreeItemExpandedCommand = new RelayCommand<object>(p => TreeItemExpandedExecuted(p));
return _TreeItemExpandedCommand;
}
}
private void TreeItemExpandedExecuted(object args)
{
}
When I expand a node nothing happens. There are no binding errors, and the Command's getter fires when it starts, but the TreeItemExpandedExecuted never fires.
I tried using the event itself:
<TreeView TreeViewItem.Expanded="TreeViewItem_Expanded">
...
</TreeView/>
and
private void TreeViewItem_Expanded(object sender, RoutedEventArgs e)
{
TreeViewItem tvi = e.OriginalSource as TreeViewItem;
if (tvi != null)
{
}
}
But still nothing.
I'm guessing this has something to do with this all being in a ControlTemplate. Anyone see what's wrong here?
If it's not broken, fix it until it is.
Everything makes sense in someone's mind.
Ya can't fix stupid.
|
|
|
|
|
I have a DataGrid bound to a list of models. On the ViewModel is a property called AreFieldsEnabled. When the user clicks Edit the it sets AreFieldsEnabled to true and the datagrid becomes enabled/
I have this style
<Style x:Key="dataGridCurrencyCellStyle"
BasedOn="{StaticResource dataGridCellStyle}"
TargetType="{x:Type DataGridCell}">
<Setter Property="Width" Value="75"/>
<Setter Property="TextBlock.TextAlignment" Value="Left"/>
<Setter Property="TextBlock.Text" Value="{Binding StringFormat=C}"/>
<Setter Property="IsEnabled" Value="{Binding DataContext.AreFieldsEnabled, ElementName=budgetControl}"/>
</Style>
What I need do now is a change it to a MultiTrigger. On the model is a bool property called IsCellEnabled which I set programmatically when loading the data.
<Style x:Key="dataGridCurrencyCellStyle"
BasedOn="{StaticResource dataGridCellStyle}"
TargetType="{x:Type DataGridCell}">
<Setter Property="Width" Value="75"/>
<Setter Property="TextBlock.TextAlignment" Value="Left"/>
<Setter Property="TextBlock.Text" Value="{Binding StringFormat=C}"/>
<Setter Property="IsEnabled" Value="False"/>
<Style.Triggers>
<MultiTrigger>
<MultiTrigger.Conditions>
<Condition Property="AreFieldsEnabled" Value="True" />
<Condition Property="IsCellEnabled " Value="True" />
</MultiTrigger.Conditions>
<MultiTrigger.Setters>
<Setter Property="IsEditing" Value="True" />
</MultiTrigger.Setters>
</MultiTrigger>
</Style.Triggers>
</Style>
Now, both conditions are wrong and won't compile.
So, the AreFieldsEnabled property is on the ViewModel. The IsCellEnabled property is on the Model bound to the grid.
What's the right way to do this?
If it's not broken, fix it until it is.
Everything makes sense in someone's mind.
Ya can't fix stupid.
modified 12-Apr-22 13:25pm.
|
|
|
|
|
Use a MultiDataTrigger when the conditions depend on a binding rather than the styled control's properties.
<Style.Triggers>
<MultiDataTrigger>
<MultiDataTrigger.Conditions>
<Condition Binding="{Binding DataContext.AreFieldsEnabled, ElementName=budgetControl}" Value="True" />
<Condition Binding="{Binding IsCellEnabled}" Value="True" />
</MultiDataTrigger.Conditions>
<MultiDataTrigger.Setters>
<Setter Property="IsEditing" Value="True" />
</MultiDataTrigger.Setters>
</MultiDataTrigger>
</Style> MultiDataTrigger Class (System.Windows) | Microsoft Docs[^]
WPF MultiTrigger and MultiDataTrigger - The complete WPF tutorial[^]
"These people looked deep within my soul and assigned me a number based on the order in which I joined."
- Homer
|
|
|
|
|
Thanks. That only partly fixed it
<Style x:Key="dataGridCurrencyCellStyle"
BasedOn="{StaticResource dataGridCellStyle}"
TargetType="{x:Type DataGridCell}">
<Setter Property="Width" Value="75"/>
<Setter Property="TextBlock.TextAlignment" Value="Left"/>
<Setter Property="TextBlock.Text" Value="{Binding StringFormat=C}"/>
<Setter Property="IsEnabled" Value="False"/>
<Style.Triggers>
<MultiDataTrigger>
<MultiDataTrigger.Conditions>
<Condition Binding="{Binding DataContext.AreFieldsEnabled, ElementName=budgetControl}" Value="True" />
<Condition Binding="{Binding IsCellEnabled}" Value="True" />
</MultiDataTrigger.Conditions>
<MultiDataTrigger.Setters>
<Setter Property="IsEnabled" Value="True" />
</MultiDataTrigger.Setters>
</MultiDataTrigger>
</Style.Triggers>
</Style>
The 2nd condition with the IsCellEnabled isn't finding the model the row is bound to. Not sure how to reference that from this style. I get a binding error "BindingExpression path error: 'IsCellEnabled' property not found on 'object' ''DataRowView'"
If it's not broken, fix it until it is.
Everything makes sense in someone's mind.
Ya can't fix stupid.
|
|
|
|
|
I'm still stuck on this. I can't seem to get the second trigger condition to bind correctly. How would I bind the condition to the IsCellEnabled property on the model?
If it's not broken, fix it until it is.
Everything makes sense in someone's mind.
Ya can't fix stupid.
modified 13-Apr-22 14:13pm.
|
|
|
|
|
Kevin Marois wrote: 'IsCellEnabled' property not found on 'object' ''DataRowView'"
You're not binding to the model; you're binding to a DataView .
You could try {Binding [IsCellEnabled]} , assuming that is a column in your view.
"These people looked deep within my soul and assigned me a number based on the order in which I joined."
- Homer
|
|
|
|
|
I am generating a datagrid on the fly at runtime. See this pic .
I am generating a Data Table, and the go through each column of the table and create DataGridColumns. The first column, the Type, is read only. The rest are editable and will accept money values.
I am trying to apply the cell style in code behind:
foreach (string item in columnNames)
{
Binding binding = new Binding(item);
string styleName = "";
if (item == "Type")
{
binding.Mode = BindingMode.OneTime;
styleName = "budgetGridCellStyle";
}
else
{
binding.Mode = BindingMode.TwoWay;
binding.UpdateSourceTrigger = UpdateSourceTrigger.PropertyChanged;
styleName = "dataGridCurrencyCellStyle";
}
var style = Application.Current.FindResource(styleName) as Style;
var col = new DataGridTextColumn()
{
Header = item,
Binding = binding,
Visibility = Visibility.Visible,
CellStyle = style
};
DataGridColumns.Add(col);
}
Here is the DataGridCellStyle
<Style x:Key="dataGridCurrencyCellStyle"
BasedOn="{StaticResource dataGridCellStyle}"
TargetType="{x:Type DataGridCell}">
<Setter Property="Width" Value="75"/>
<Setter Property="TextBlock.TextAlignment" Value="Right"/>
<Setter Property="TextBlock.Text" Value="{Binding StringFormat={}{0:0.##}}"/>
<Setter Property="IsEnabled" Value="{Binding DataContext.AreFieldsEnabled, ElementName=budgetControl}"/>
</Style>
Yet, AFTER I save changes, the cells end up with 4 decimal places.
Anyone have any ideas on how to fix this?
If it's not broken, fix it until it is.
Everything makes sense in someone's mind.
Ya can't fix stupid.
modified 7-Apr-22 11:25am.
|
|
|
|