|
geomeo123 wrote: Do I put the above in my wpf form load event and make these public so that my modelview class can see them?
No. The ViewModel should not have any reference to the view.
The quick fix would be to move the serial port comms into the ViewModel.
A better option would probably be to move it to a separate "service" class consumed by the ViewModel, particularly if you want to introduce unit tests for your ViewModel classes.
"These people looked deep within my soul and assigned me a number based on the order in which I joined."
- Homer
|
|
|
|
|
Ok so I put them in ViewModel as a quick fix for now, but how would I call that from my xaml form? The xaml loaded event doesn't allow me to bind to my static resource(thinking I could just do another Icommand). Maybe because my static resource is called after I'm putting in loaded in xaml, but I can't think of any other way.
|
|
|
|
|
The typical solution would be to use an "attached behaviour" to bind the Loaded event to your command.
Introduction to Attached Behaviors in WPF[^]
For example:
public static class LoadedBehavior
{
public static readonly DependencyProperty LoadedCommandProperty = DependencyProperty.RegisterAttached(
"LoadedCommand",
typeof(ICommand),
typeof(LoadedBehavior),
new PropertyMetadata(null, OnLoadedCommandChanged));
public static ICommand GetLoadedCommand(FrameworkElement obj)
{
return (ICommand)obj.GetValue(LoadedCommandProperty);
}
public static void SetLoadedCommand(FrameworkElement obj, ICommand value)
{
obj.SetValue(LoadedCommandProperty, value);
}
private static void OnLoadedCommandChanged(DependencyObject obj, DependencyPropertyChangedEventArgs e)
{
FrameworkElement element = obj as FrameworkElement;
if (element == null) return;
if (e.OldValue == null)
{
element.Loaded += OnLoaded;
}
else if (e.NewValue == null)
{
element.Loaded -= OnLoaded;
}
}
public static readonly DependencyProperty LoadedCommandParameterProperty = DependencyProperty.RegisterAttached(
"LoadedCommandParameter",
typeof(object),
typeof(LoadedBehavior),
new PropertyMetadata(null));
public static object GetLoadedCommandParameter(FrameworkElement obj)
{
return obj.GetValue(LoadedCommandParameterProperty);
}
public static void SetLoadedCommandParameter(FrameworkElement obj, object value)
{
obj.SetValue(LoadedCommandParameterProperty, value);
}
private static void OnLoaded(object sender, RoutedEventArgs e)
{
FrameworkElement element = sender as FrameworkElement;
if (element == null) return;
ICommand command = GetLoadedCommand(element);
if (command == null) return;
object parameter = GetLoadedCommandParameter(element);
command.Execute(parameter);
}
}
"These people looked deep within my soul and assigned me a number based on the order in which I joined."
- Homer
|
|
|
|
|
|
Thank you much Richard. I think I got it. Thanks again!
|
|
|
|
|
I'm trying to use a WrapPanel inside an ItemsControl. I'm following this[^].
The difference is that mine is bound to a list of objects called Backups.
Here's what I have. When I run it, I don't see any of the data.
<Border Grid.Row="1"
CornerRadius="20"
Margin="35"
Padding="10"
Background="Tan"
BorderThickness="3"
BorderBrush="SteelBlue">
<ScrollViewer VerticalScrollBarVisibility="Auto"
Background="Teal"
Margin="10">
<ItemsControl ItemsSource="{Binding Backups}">
<ItemsControl.ItemTemplate>
<DataTemplate>
<Border Background="Salmon"
BorderBrush="Blue"
BorderThickness="3">
<StackPanel Orientation="Vertical">
<Rectangle Margin="5"
Width="100"
Height="100"
Fill="Yellow"
HorizontalAlignment="Center"/>
<TextBlock Text="THIS IS A TEST"
HorizontalAlignment="Center"
Margin="5"/>
</StackPanel>
</Border>
</DataTemplate>
</ItemsControl.ItemTemplate>
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<WrapPanel IsItemsHost="True"/>
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
</ItemsControl>
</ScrollViewer>
</Border>
In theory, theory and practice are the same. But in practice, they never are.”
If it's not broken, fix it until it is.
Everything makes sense in someone's mind.
modified 29-May-24 22:23pm.
|
|
|
|
|
If you remove the ItemsPanel , do you see the items?
If not, are there any binding errors logged in the Visual Studio output window?
"These people looked deep within my soul and assigned me a number based on the order in which I joined."
- Homer
|
|
|
|
|
I removed the ItemsPanel, and there are no binding errors, yet I still see nothing.
Also, I just created a quick test app doing the same thing, and it works:
GitHub - MaroisConsulting/Marois.WrapPanelDemo
In theory, theory and practice are the same. But in practice, they never are.”
If it's not broken, fix it until it is.
Everything makes sense in someone's mind.
|
|
|
|
|
Kevin Marois wrote: I removed the ItemsPanel, and there are no binding errors, yet I still see nothing.
Which means the problem is nothing to do with the items panel; either it's not binding to the collection, or the collection is empty.
"These people looked deep within my soul and assigned me a number based on the order in which I joined."
- Homer
|
|
|
|
|
I am facing an exception while WebView initialize. It is working perfectly fine when i debug my code on VS 2019 but when i make an installer and install it on VM Windows 10 Machine it gives me an exception which i can get with help of Logs.
I have added UDF as well in my client machine and install Microsoft edge runtime(124.0.2478.97)
Please Suggest any one what i need to add to resolve this issue.
Code Block
MainWindow.xaml.cs
using Microsoft.Web.WebView2.Core;
using Microsoft.Web.WebView2.Wpf;
public MainWindow()
{
InitializeComponent();
InitializeAndNavigateAsync( url);
}
public async Task InitializeAndNavigateAsync(string url)
{
await InitializeWebViewAsync();
await NavigateToUrlAsync(url);
}
private async Task InitializeWebViewAsync()
{
try
{
log.Debug($"WebView2 initialize start");
await webView.EnsureCoreWebView2Async(null);
log.Debug($"WebView2 initialize stop");
}
catch (Exception e)
{
log.Debug($"WebView2 initialization failed.{e.Message}");
log.Debug($"WebView2 initialization failed.{e.StackTrace}");
}
}
private async Task NavigateToUrlAsync(string url)
{
try
{
log.Debug($"WebView2 NavigateToUrlAsync start");
webView.CoreWebView2.Navigate(url);
log.Debug($"WebView2 NavigateToUrlAsync stop");
}
catch (Exception e)
{
log.Debug($"WebView2 NavigateToUrlAsync failed.{e.Message}");
log.Debug($"WebView2 NavigateToUrlAsync failed.{e.StackTrace}");
}
}
Exception is :
WebView2 initialization failed.Server execution failed (Exception from HRESULT: 0x80080005 (CO_E_SERVER_EXEC_FAILURE))
2024-05-14 06:34:45.4923|DEBUG|debug|WebView2 initialization failed. at System.Runtime.InteropServices.Marshal.ThrowExceptionForHRInternal(Int32 errorCode, IntPtr errorInfo)
at Microsoft.Web.WebView2.Core.CoreWebView2Environment.<CreateCoreWebView2ControllerAsync>d__80.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
at Microsoft.Web.WebView2.Wpf.WebView2.<>c__DisplayClass32_0.<<EnsureCoreWebView2Async>g__Init|0>d.MoveNext()
2024-05-14 06:34:45.4923|DEBUG|debug|WebView2 initialization failed.mscorlib
|
|
|
|
|
In your InitializeWebViewAsync method, try creating a CoreWebView2Environment object (you'll need to give it a folder path to use) and passing that to the EnsureCoreWebView2Async method.
|
|
|
|
|
I have a standard C#, WPF, and PRISM project, and I wanted to have one module per tab item. But I want to bind the header of a property in the ViewModel directly to the parent TabItem.
I tried this (among other things such as Content.DataContext.Message etc.) :
<TabItem Header="{Binding DataContext.Message, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type UserControl}}}">
<ContentControl prism:RegionManager.RegionName="{x:Static core:RegionNames.ContentRegion}"></ContentControl>
</TabItem>
I have a distinct feeling I have done this before, but I cannot figure it out at the moment, so any suggestions?
|
|
|
|
|
I'm building and populating a DataGrid in a viewmodel.
Here's what I'm making[^]
The two columns on the right, AutoAdjustment and AutoPosting, are combo boxes where the user can selecte 'Y' or 'N'. These are the only editable columns.
For my source data, I have a list of objects called ProcoessingOutputEntries, each with a list of column objects. It's basically a 'row' object with a dynamic collection of columns on it:
private List<ProcessingOutputEntryEntity> _ProcesssingOutputEntries;
public List<ProcessingOutputEntryEntity> ProcesssingOutputEntries
{
get { return _ProcesssingOutputEntries; }
set
{
if (_ProcesssingOutputEntries != value)
{
_ProcesssingOutputEntries = value;
RaisePropertyChanged(nameof(ProcesssingOutputEntries));
}
}
}
and
public class ProcessingOutputEntryEntity : _EntityBase
{
private List<ColumnInfoEntity> _ProcesssingOutputColumns;
public List<ColumnInfoEntity> ProcesssingOutputColumns
{
get { return _ProcesssingOutputColumns; }
set
{
if (_ProcesssingOutputColumns != value)
{
_ProcesssingOutputColumns = value;
RaisePropertyChanged(nameof(ProcesssingOutputColumns));
}
}
}
}
and
public class ColumnInfoEntity : _EntityBase
{
private string _ColumnName;
public string ColumnName
{
get { return _ColumnName; }
set
{
if (_ColumnName != value)
{
_ColumnName = value;
RaisePropertyChanged(nameof(ColumnName));
}
}
}
private ColumnSources _ColumnSource;
public ColumnSources ColumnSource
{
get { return _ColumnSource; }
set
{
if (_ColumnSource != value)
{
_ColumnSource = value;
RaisePropertyChanged(nameof(ColumnSource));
}
}
}
private ColumnTypes _ColumnType;
public ColumnTypes ColumnType
{
get { return _ColumnType; }
set
{
if (_ColumnType != value)
{
_ColumnType = value;
RaisePropertyChanged(nameof(ColumnType));
}
}
}
private int _ColumnWidth;
public int ColumnWidth
{
get { return _ColumnWidth; }
set
{
if (_ColumnWidth != value)
{
_ColumnWidth = value;
RaisePropertyChanged(nameof(ColumnWidth));
}
}
}
private string _DisplayAs;
public string DisplayAs
{
get { return _DisplayAs; }
set
{
if (_DisplayAs != value)
{
_DisplayAs = value;
RaisePropertyChanged(nameof(DisplayAs));
}
}
}
private int _IndexPosition;
public int IndexPosition
{
get { return _IndexPosition; }
set
{
if (_IndexPosition != value)
{
_IndexPosition = value;
RaisePropertyChanged(nameof(IndexPosition));
}
}
}
private bool _IsUserEditable = true;
public bool IsUserEditable
{
get { return _IsUserEditable; }
set
{
if (_IsUserEditable != value)
{
_IsUserEditable = value;
RaisePropertyChanged(nameof(IsUserEditable));
}
}
}
private object _Data;
public object Data
{
get { return _Data; }
set
{
if (_Data != value)
{
_Data = value;
RaisePropertyChanged(nameof(Data));
}
}
}
public override string ToString()
{
return $"{ColumnSource} {IndexPosition} {ColumnName}";
}
}
I handle the WindowLoaded event to create the grid in my ViewModel:
private void WindowLoadedExecuted()
{
_results.ProcesssingOutputEntries.ForEach(x => x.Id = Guid.NewGuid());
foreach (var entry in _results.ProcesssingOutputEntries)
{
var col = new ColumnInfoEntity
{
ColumnName = "Id",
Data = entry.Id.ToString()
};
entry.ProcesssingOutputColumns.Insert(0, col);
}
DataColumn column = null;
var firstEntry = _results.ProcesssingOutputEntries.FirstOrDefault();
foreach (var col in firstEntry.ProcesssingOutputColumns)
{
column = new DataColumn
{
DataType = Type.GetType("System.String"),
ReadOnly = false
};
ColumnsDataTable.Columns.Add(column);
}
var autoAdjColIndex = -1;
var autoPostColIndex = -1;
var autoAdjCol = GetProcessingOutputColumn(ColumnTypes.AutoAdjustment);
if(autoAdjCol != null)
{
autoAdjColIndex = firstEntry.ProcesssingOutputColumns.IndexOf(autoAdjCol);
}
var autoPostCol = GetProcessingOutputColumn(ColumnTypes.AutoPosting);
if (autoPostCol != null)
{
autoPostColIndex = firstEntry.ProcesssingOutputColumns.IndexOf(autoPostCol);
}
string[] columnNames = (from dc in ColumnsDataTable.Columns.Cast()
select dc.ColumnName).ToArray();
var textBoxStyle = new Style();
textBoxStyle.Setters.Add(new Setter(TextBox.TextAlignmentProperty, TextAlignment.Right));
var comboBoxStyle = new Style();
comboBoxStyle.Setters.Add(new EventSetter(ComboBox.SelectionChangedEvent, new SelectionChangedEventHandler(ComboSelectionChanged)));
int index = 0;
foreach (string columnName in columnNames)
{
var binding = new Binding(columnName);
if (index == autoAdjColIndex || index == autoPostColIndex)
{
var col = new DataGridComboBoxColumn()
{
Header = firstEntry.ProcesssingOutputColumns[index].ColumnName,
ItemsSource = new List { "Y", "N" },
Visibility = Visibility.Visible,
TextBinding = binding,
IsReadOnly = false,
CellStyle = comboBoxStyle,<br />
};
DataGridColumns.Add(col);
}
else
{
var col = new DataGridTextColumn()
{
Header = firstEntry.ProcesssingOutputColumns[index].ColumnName,
Binding = binding,
Visibility = Visibility.Visible,
IsReadOnly = true,
CellStyle = textBoxStyle
};
DataGridColumns.Add(col);
}
index++;
}
LoadData();
}
Here's how the data is loaded
private void LoadData()
{
ColumnsDataTable.Clear();
foreach (var processingEntry in _results.ProcesssingOutputEntries)
{
DataRow row = ColumnsDataTable.NewRow();
ColumnsDataTable.Rows.Add(row);
var index = 0;
foreach (var col in processingEntry.ProcesssingOutputColumns)
{
row[index] = col.Data;
index++;
}
}
}
The ComboBox column style handles the SelectionChanged event:
var comboBoxStyle = new Style();
comboBoxStyle.Setters.Add(new EventSetter(ComboBox.SelectionChangedEvent, new SelectionChangedEventHandler(ComboSelectionChanged)));
and
private void ComboSelectionChanged(object sender, SelectionChangedEventArgs e)
{
var comboBox = e.Source as ComboBox;
var dataGrid = WPFTools.GetVisualParent(comboBox);
var dataRowView = dataGrid.SelectedItem as DataRowView;
if(dataRowView != null)
{
var newSelection = e.AddedItems[0];
var rowId = dataRowView.Row[0].ToString();
}
}
So, the question is, in this event handler, how do I set the newly selected value back to the source row? It seems like I need to get the row, then the bound object from it. But how do I know which combox fired this event?
Thanks
In theory, theory and practice are the same. But in practice, they never are.”
If it's not broken, fix it until it is.
Everything makes sense in someone's mind.
modified 8-Apr-24 20:10pm.
|
|
|
|
|
Probably an unwanted comment but why not use a checkbox binding directly to the datasource, less clicks for the user, and no faffing around with combobox and dodgy binding. You could even add the Yes/No based on the checked state.
Never underestimate the power of human stupidity -
RAH
I'm old. I know stuff - JSOP
|
|
|
|
|
I'm sure this is a silly question....
I'm trying to port some behaviors from .Net Framewor 4.7 to Core 6.
This no longer compiles:
public class ComboBoxWatermarkBehavior : Behavior<ComboBox>
.
.
.
because it can't find Behavior<>
From what I can see from Google results, I was missing Microsoft.Xaml.Behaviors.Wpf. I added the package but it didn't do anything.
What am I missing here???
In theory, theory and practice are the same. But in practice, they never are.”
If it's not broken, fix it until it is.
Everything makes sense in someone's mind.
|
|
|
|
|
You definitely have using Microsoft.Xaml.Behaviors; in this file? As long as you Nugeted from here[^] that should be all you need.
|
|
|
|
|
Hello,
I'd tried to reduce the problem.
I've this UserControl
public class TestControl : Label
{
public static readonly DependencyProperty dependencyPropertyTestInfo =
DependencyProperty.Register("TestInfo", typeof(string), typeof(TestControl),
new PropertyMetadata("", new PropertyChangedCallback(ChangeTestInfo)));
public string TestInfo
{
get => (string)GetValue(dependencyPropertyTestInfo);
set => SetValue(dependencyPropertyTestInfo, value);
}
private static void ChangeTestInfo(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
var testControl = (TestControl)d;
testControl.TestInfo = (string)e.NewValue;
}
}
This is the essential part of MainWindow.xaml:
<StackPanel>
<local:TestControl Content="TestControl" x:Name="tct" TestInfo="{Binding TestInfoView}"/>
<Button Content="show TestInfo by Button-Click in xaml.cs" x:Name="BtnShow" Click="BtnShow_Click"/>
<Button Content="set new TestInfo" Name="BtnNewTestInfo" Command="{Binding NewTestInfoCommand}"/>
</StackPanel>
Its bounded in MainWindow.xaml.cs to DataContext with this ViewModel:
public class MainWindowViewModel : BindableBase
{
private int counter;
private string _testInfoView;
public string TestInfoView
{
get { return _testInfoView; }
set { SetProperty(ref _testInfoView, value); }
}
public DelegateCommand NewTestInfoCommand { get; }
public MainWindowViewModel()
{
NewTestInfoCommand = new DelegateCommand(OnNewTestInfoCommand);
TestInfoView = "Info from ctor";
}
private void OnNewTestInfoCommand()
{
string newInfo = $"Info No. {++counter}";
Debug.WriteLine($"{MethodBase.GetCurrentMethod().Name}: {nameof(TestInfoView)}=«{TestInfoView}» -> «{newInfo}»");
TestInfoView = newInfo;
}
}
I've added a "Debug.WriteLine" in MainWindow.xaml.cs
private void BtnShow_Click(object sender, RoutedEventArgs e)
{
Debug.WriteLine($"{MethodBase.GetCurrentMethod().Name}: {nameof(tct.TestInfo)}={tct.TestInfo}");
}
After starting the app
1. I've clicked "BtnShow" this is the debug-info:
BtnShow_Click: TestInfo=Info from ctor
2. I've clicked "BtnNewTestInfo" this is the debug-info:
OnNewTestInfoCommand: TestInfoView=«Info from ctor» -> «Info No. 1»
3. I've clicked "BtnShow" this is the debug-info:
BtnShow_Click: TestInfo=Info from ctor
Now my question is: why ViewModel-Command doesn't change the content of TestControl?
Explanation of the goal:
Based on a WrapPanel I'll add in Children ToggleButton as a representation of tags in a Control named "TagPanel". By clicking the ToggleButton I can define the Tags of a given dataset record.
To define the ToggleButton I'll set in ViewModel a string property "TagDef" with comma-separated values like "red,blue,green" to get three buttons.
And by setting a string property "CheckedTag" (i.e "green,red") I'll set IsChecked of the concerned buttons.
But by setting in viewmodel, the properties aren't changed in TagPanel. Now I'm using events - what a pity.
modified 26-Feb-24 7:39am.
|
|
|
|
|
XAML data-binding to dependency properties does not use the property getter or setter. It calls SetValue directly on the DependencyProperty instance. Any code that needs to execute when the property value changes needs to be in the PropertyChangedCallback method.
#118 – Don’t Add Code to Dependency Property Getter/Setter | 2,000 Things You Should Know About WPF[^]
You've also forgotten to raise the PropertyChanged event from your viewmodel. Assuming the usual definition of BindableBase , you probably meant to write something like:
private string _testInfoView;
public string TestInfoView
{
get { return _testInfoView; }
set { SetProperty(ref _testInfoView, value); }
} The SetProperty method will update the field and raise the PropertyChanged event for you.
"These people looked deep within my soul and assigned me a number based on the order in which I joined."
- Homer
|
|
|
|
|
Thank you for your answer.
I have changed my test project and adapted the original message.
1. removed all Debug.Writeline in TestControl
2. in ViewModel
set { SetProperty(ref _testInfoView, value); }
3. Added a button BtnShow to see in it's Click in xaml.cs the content of TestInfo property
In the original post under "After starting the app" I'd explained what I've done.
But the ViewModel-command didn't change the property.
I've added the code to GitHub - iwangoll/TestBinding: ViewModel-command didn't change the DependencyProperty.[^]
|
|
|
|
|
That's a strange way of sharing code - uploading a 7zip file to GitHub, rather than uploading your code itself.
The first thing that jumps out is the PropertyChangedCallback :
private static void ChangeTestInfo(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
var testControl = (TestControl)d;
testControl.TestInfo = (string)e.NewValue;
} Thankfully, WPF doesn't call the "property changed" callback if you set the property to the same value it's already set; otherwise, you'd end up with a stack overflow here.
As far as I can see, you want to log the fact that the property has changed, not change the property again:
private static void ChangeTestInfo(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
Debug.WriteLine($"TestInfo changed from '{e.OldValue}' to '{e.NewValue}'.");
}
Beyond that, your code works as expected. Clicking the "set new TestInfo" button shows the new value being set in the debug console. Clicking the "show TestInfo by Button-Click in xaml.cs" button shows the expected new value in the debug console.
Perhaps you were expecting the content of your test control to update? But that's not going to happen: you've set it to the fixed string "TestControl", which isn't bound to anything.
If you want to show the value on the screen, then change your markup to:
<local:TestControl Content="{Binding Path=TestInfo, ElementName=tct}" x:Name="tct" TestInfo="{Binding TestInfoView}"/>
"These people looked deep within my soul and assigned me a number based on the order in which I joined."
- Homer
|
|
|
|
|
Dear Richard, many thanks for your help.
Now it works. And I think I understand the functionality of DependencyProperty much better now.
And sorry for the GitHub & 7z. I'm very new there.
|
|
|
|
|
I have a tab control, and I have a header template and style:
<!Tab Item Header Template>
<DataTemplate x:Key="CustomHeaderTemplate">
<DockPanel LastChildFill="True">
<TextBlock Text="{Binding FileName}"
VerticalAlignment="Center"
FontSize="14"/>
<Button Command="{Binding DataContext.CloseTabCommand, RelativeSource={RelativeSource AncestorType={x:Type Window}}}"
CommandParameter="{Binding}"
VerticalAlignment="Center"
Height="22"
Width="22"
Background="SteelBlue"
Margin="3,0,0,0">
<Path Data="M1,9 L9,1 M1,1 L9,9"
Stroke="White"
StrokeThickness="2" />
</Button>
</DockPanel>
</DataTemplate>
<!Tab Item Style>
<Style TargetType="TabItem">
<Setter Property="ContextMenu">
<Setter.Value>
<ContextMenu DataContext="{Binding Path=PlacementTarget.DataContext, RelativeSource={RelativeSource Self}}" >
<MenuItem Header="Close Tab"
Command="{Binding Source={StaticResource Proxy}, Path=Data.CloseTabCommand}"
CommandParameter="{Binding}"/>
<MenuItem Header="Close All Tabs"
Command="{Binding Source={StaticResource Proxy}, Path=Data.CloseAllTabsCommand}"
CommandParameter="{Binding}"/>
<MenuItem Header="Close All But This"
Command="{Binding Source={StaticResource Proxy}, Path=Data.CloseAllButThisTabCommand}"
CommandParameter="{Binding}"/>
</ContextMenu>
</Setter.Value>
</Setter>
</Style>
The problem is that if I right-click a tab that is NOT selected, and choose one of the close options, the SELECTED tab is closed. How can I specify that correct tab item in the command?
In theory, theory and practice are the same. But in practice, they never are.”
If it's not broken, fix it until it is.
Everything makes sense in someone's mind.
|
|
|
|
|
I have a window with bound fields that I'm validating with INotifyDataErrorInfo. There is a button on the window that opens a dialog that the user needs to complete before all of the data is truly valid.
What I'd like is to to have a validation message next to the button. But since the button is not bound, I can't really use INotifyDataErrorInfo for this.
What's the right way to do this?
In theory, theory and practice are the same. But in practice, they never are.”
If it's not broken, fix it until it is.
Everything makes sense in someone's mind.
modified 3-Jan-24 1:29am.
|
|
|
|
|
I have a CustomControl with three DP's. On startup the change callbacks fire for all three, but I need to know when they have ALL fired, so I can then set up the control using their data. The Initialized gets called first, then the DP's, so I can't rely on that.
I was thinking of creating a bool flag for each, and when each are true, then go ahead and load my control using all the DP's, but I'm wondering if there's another way.
An event that fires AFTER the DP's would be nice, but I don't see one.
In theory, theory and practice are the same. But in practice, they never are.”
If it's not broken, fix it until it is.
Everything makes sense in someone's mind.
|
|
|
|
|
If I understand what you're looking for, I use the control's Loaded event. At that point the control is ready to go and all of the Dependency properties should be set.
".45 ACP - because shooting twice is just silly" - JSOP, 2010 ----- You can never have too much ammo - unless you're swimming, or on fire. - JSOP, 2010 ----- When you pry the gun from my cold dead hands, be careful - the barrel will be very hot. - JSOP, 2013
|
|
|
|
|