Thanks, mvermef, but that's not correct. Version 1.5.2 does validate out of the box - at least for the TextBox. I'll try the method mention in the link above to see what happens.
↧
New Post: Validation on ComboBox Issue
↧
New Post: ActionMessage Not in Namespace
I have version 2 loaded, but now the Bootstrapper is not supported? I'll start searching, but what's the correct way to setup the project now?
↧
↧
New Post: ActionMessage Not in Namespace
Ok - I have the bootstrapper working. I had to make the constructor public instead of static and call base(true). Then inside the constructor make a call to base.Start().
public AppBootstrapper() : base(true)
{
--- other startup code
Start();
}
Then, in the OnStartup override, make a call to DisplayRootViewFor... protected override void OnStartup(object sender, System.Windows.StartupEventArgs e)
{
// do custom code here which you want to run on startup
DisplayRootViewFor<MainWindowViewModel>();
base.OnStartup(sender, e);
}
So, back in action and the XAML markup for cal:Message.Attach now works with Blend and the VS designer. BTW, the namespace for using cal: uses Platform:xmlns:cal="clr-namespace:Caliburn.Micro;assembly=Caliburn.Micro.Platform"
↧
New Post: Custom Binding for MultiSelectComboBox
Setup
VS 2010
WPF 4.0
CM 1.3.1
I am using the MultiSelectComboBox found at the link below. It's a ComboBox that includes a checkbox for each Item and allows multiple selections. Items Source and selected items are of type Dictionary(Of String, Object).
http://www.codeproject.com/Articles/563862/Multi-Select-ComboBox-in-WPF?msg=4744582#xx4744582xx
My attempt to set up custom binding in the bootstrapper looks like this:
Thanks, CM is great!
VS 2010
WPF 4.0
CM 1.3.1
I am using the MultiSelectComboBox found at the link below. It's a ComboBox that includes a checkbox for each Item and allows multiple selections. Items Source and selected items are of type Dictionary(Of String, Object).
http://www.codeproject.com/Articles/563862/Multi-Select-ComboBox-in-WPF?msg=4744582#xx4744582xx
My attempt to set up custom binding in the bootstrapper looks like this:
ConventionManager.AddElementConvention(Of LPCore.Controls.MultiSelectComboBox) _
(LPCore.Controls.MultiSelectComboBox.SelectedItemsProperty, "Text", "ValueChanged").GetBindableProperty = Function(foundControl As DependencyObject)
Dim element = DirectCast(foundControl, MultiSelectComboBox)
Dim useViewModel = element.ContentTemplate Is Nothing
If useViewModel Then
Return View.ModelProperty
End If
Return LPCore.Controls.MultiSelectComboBox.SelectedItemsProperty
End Function
I strongly suspect that my custom binding is wrong, but I need help to correct it. At run time I get "Cannot find view for... in the UI, instead of the control.Thanks, CM is great!
↧
New Post: Composing a screen out of multiple usercontrols
I think that a better solution might be the one shown at: http://stackoverflow.com/questions/6230603/resolving-external-user-control-xname-convention-bindings-in-caliburn-micro
This solution consists of:
<customControls:CompanyNameControl cal:Bind.Model="{Binding}"/>
In this solution there is mention of the view model which is something that the view should know nothing about.
This solution consists of:
<customControls:CompanyNameControl cal:Bind.Model="{Binding}"/>
In this solution there is mention of the view model which is something that the view should know nothing about.
↧
↧
New Post: window manager and multiple UI threads
I have a WPF application in which I'm using caliburn.
My main window utilizes WPF 3D component which runs a machine simulation thats UI intensive.
On the main window, i have a button that opens up a 2nd window (not modal) which contains simple WPF form elements such as buttons, listboxes,etc. In code, i would simply call ShowWindow method via IWindowManager available to me via the ImportingConstructor.
The problem is that the performance on the 2nd window is undesirably slow since the main window is utilizing the UI thread via 3d component. How would i use the ShowWindow method in such a way that it puts the 2nd window on a 2nd UI thread? I have seen some articles that have a solution for this but not using caliburn methods. Any idea or am i going about this the wrong way?
My main window utilizes WPF 3D component which runs a machine simulation thats UI intensive.
On the main window, i have a button that opens up a 2nd window (not modal) which contains simple WPF form elements such as buttons, listboxes,etc. In code, i would simply call ShowWindow method via IWindowManager available to me via the ImportingConstructor.
The problem is that the performance on the 2nd window is undesirably slow since the main window is utilizing the UI thread via 3d component. How would i use the ShowWindow method in such a way that it puts the 2nd window on a 2nd UI thread? I have seen some articles that have a solution for this but not using caliburn methods. Any idea or am i going about this the wrong way?
↧
New Post: Composing a screen out of multiple usercontrols
Sorry for the type on my previous post. It should say "In this solution is NO mention of the view model..."
↧
New Post: Error Hosting WindowsFormsHost in Caliburn micro app
Help needed.
{"The invocation of the constructor on type 'Planviewer.Utils.PDFViewerHost' that matches the specified binding constraints threw an exception."}
Here is the XAML
<utils:PDFViewerHost x:Name="PDFViewer" PDFPath="{Binding CurrentPDFFile}" MakeDirty="{Binding IsDirty}" Margin="0" />
Here is the class
{"The invocation of the constructor on type 'Planviewer.Utils.PDFViewerHost' that matches the specified binding constraints threw an exception."}
Here is the XAML
<utils:PDFViewerHost x:Name="PDFViewer" PDFPath="{Binding CurrentPDFFile}" MakeDirty="{Binding IsDirty}" Margin="0" />
Here is the class
public class PDFViewerHost : WindowsFormsHost
{
public static readonly DependencyProperty PDFPathProperty = DependencyProperty.Register(
"PDFPath", typeof(string), typeof(PDFViewerHost), new PropertyMetadata(PDFPathPropertyChanged));
public static readonly DependencyProperty MakeDirtyProperty = DependencyProperty.Register(
"MakeDirty", typeof(bool), typeof(PDFViewerHost), new PropertyMetadata(MakeDirtyPropertyChanged));
private readonly PDFViewer wrappedControl;
public PDFViewerHost()
{
wrappedControl = new PDFViewer();
Child = wrappedControl;
}
public string PDFPath
{
get { return (string)GetValue(PDFPathProperty); }
set
{
SetValue(PDFPathProperty, value);
}
}
public bool MakeDirty
{
get { return (bool)GetValue(MakeDirtyProperty); }
set
{
SetValue(MakeDirtyProperty, value);
}
}
private static void PDFPathPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
PDFViewerHost host = (PDFViewerHost)d;
host.wrappedControl.PDFFilePath = (string)e.NewValue;
}
private static void MakeDirtyPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
PDFViewerHost host = (PDFViewerHost)d;
host.wrappedControl.MakeDirty = true;
}
}
↧
New Post: window manager and multiple UI threads
To spawn a Window on a new thread, you just need to initialize a Dispatcher on a new thread, and run the Window constructor on such a thread (as you probably now).
So, you would just need to spawn the new thread, initialize the Dispatcher and call IWindowManager.ShowWindow on such a thread (or create an extension method to wrap it up). The issue with CM is that it statically refers to a single Dispatcher, when invoking Execute.OnUIThread and alike (in particular, the dispatcher used to build up the bootstrapper), which can lead to lots of issues when dealing with multiple UI threads.
A possible (general) solution to this problem, would be to parametrize every call that is redirected to the dispatcher with a thread affinity context, and store an association between the thread affinity context and an actual Dispatcher. Unfortunally, this is quite a complex modification of CM base-code, and I dubt (haven't tested, tho) that it can be achieved just extending the standard version of CM.
A possible work-around, would be to procede this way:
Note that these are just speculations, and are not based on a real-life experience. :)
On a side note, I have looked at a couple of SO questions (like this), and it seems to me that it would be far better to follow the proposed idea: build-up the 3D content on a separate thread, freeze the resulting model and pass it to the 3D view-port. This way, the 3D content would keep the UI thread occupied just for the time required for actual rendering. Of course, if the geometry you are dealing with changes at a quite high rate, is dynamic, or requires real-time interaction/modification, I am afraid such an approach is not usable.
So, you would just need to spawn the new thread, initialize the Dispatcher and call IWindowManager.ShowWindow on such a thread (or create an extension method to wrap it up). The issue with CM is that it statically refers to a single Dispatcher, when invoking Execute.OnUIThread and alike (in particular, the dispatcher used to build up the bootstrapper), which can lead to lots of issues when dealing with multiple UI threads.
A possible (general) solution to this problem, would be to parametrize every call that is redirected to the dispatcher with a thread affinity context, and store an association between the thread affinity context and an actual Dispatcher. Unfortunally, this is quite a complex modification of CM base-code, and I dubt (haven't tested, tho) that it can be achieved just extending the standard version of CM.
A possible work-around, would be to procede this way:
- Modify the bootstrapper OnStartup to avoid to call the base code, and create instead a new thread/dispatcher, switch the Dispatcher used in Execute.OnUIThread with the new Dispatcher.
- On the above thread specified before, call the base.Startup. This would ensure that the main window is created on a different thread while CM mechanics are still working. Thread-affinity should not be a problem, unless the main window tries to access UI objects defined on the first Dispatcher (not: Application-wide resources could be a poblem, unless frozen, but in such a case, you can re-define them as Window resources).
-
Once the 3D window has been created, switch back the Dispatcher on Execute.OnUIThread.
Note that these are just speculations, and are not based on a real-life experience. :)
On a side note, I have looked at a couple of SO questions (like this), and it seems to me that it would be far better to follow the proposed idea: build-up the 3D content on a separate thread, freeze the resulting model and pass it to the 3D view-port. This way, the 3D content would keep the UI thread occupied just for the time required for actual rendering. Of course, if the geometry you are dealing with changes at a quite high rate, is dynamic, or requires real-time interaction/modification, I am afraid such an approach is not usable.
↧
↧
New Post: Error Hosting WindowsFormsHost in Caliburn micro app
Could you check if the exception InnerException property holds useful information?
↧
Commented Unassigned: Action guard method re-evaluation [312]
I wanted to get opinions from the dev's on items like below see https://caliburnmicro.codeplex.com/discussions/442668 for original source.
On the one hand something like this could be integrated into Caliburn.Micro proper, on the other hand it could make more sense for the original author to package it up as an recipe.
Thoughts?
Every now and then, there is a new user that asks how to trigger availability update for action guards implemented as methods. I am aware that such methods are re-evaluated every time a parameter changes, but there are some cases where the evaluation of a guard depends on both the parameters and the internal state of the class providing the action. In such a scenario, it can be useful to have a way to forcefully request an availability update on the action.
I decided to provide a possible solution, involving a simple naming convention and the use of specific events: consider and action called 'Execute(...)' and the associated method guard 'CanExecute(...)'; my idea is to modify the PrepareContext implementation to check for the existence of a specific event, called 'ReEvaluateCanExecute' and, if available, attach to it and invoke UpdateAvailability whenever the event is invoked.
Since PrepareContext is an extensibility point, this feature can be easily added, without modifying the current CM code base.
The actual implementation is provided below:
``` C#
namespace ActionGuardSample
{
#region Namespaces
using System;
using System.ComponentModel;
using System.Linq;
using System.Reflection;
using Caliburn.Micro;
using Action = System.Action;
#endregion
/// <summary>
/// Static class used to provide Caliburn Micro extensions.
/// </summary>
public static class CaliburnMicroExtensions
{
#region Static Methods
/// <summary>
/// Prepares the context.
/// </summary>
/// <param name="context">The context.</param>
private static void PrepareContext(ActionExecutionContext context)
{
ActionMessage.SetMethodBinding(context);
if (context.Target != null && context.Method != null)
{
var targetType = context.Target.GetType();
var guardName = string.Format("Can{0}", context.Method.Name);
var guard = TryFindGuardMethod(context);
if (guard == null)
{
var inpc = context.Target as INotifyPropertyChanged;
if (inpc == null)
return;
guard = targetType.GetMethod(string.Format("get_{0}", guardName));
if (guard == null)
return;
var handler = (PropertyChangedEventHandler)null;
handler = ((s, e) =>
{
if (string.IsNullOrEmpty(e.PropertyName) || e.PropertyName == guardName)
{
((Action)(() =>
{
var message = context.Message;
if (message == null)
inpc.PropertyChanged -= handler;
else
message.UpdateAvailability();
})).OnUIThread();
}
});
inpc.PropertyChanged += handler;
context.Disposing += (s, e) => inpc.PropertyChanged -= handler;
context.Message.Detaching += (s, e) => inpc.PropertyChanged -= handler;
context.CanExecute = () => (bool)guard.Invoke(context.Target, MessageBinder.DetermineParameters(context, guard.GetParameters()));
}
else
{
var updateEventName = string.Format("ReEvaluate{0}", guardName);
var updateEvent = targetType.GetEvent(updateEventName);
if (updateEvent != null)
{
var target = context.Target;
EventHandler handler = null;
handler = (s, e) => ((Action)(() =>
{
var message = context.Message;
if (message == null)
updateEvent.RemoveEventHandler(target, handler);
else
message.UpdateAvailability();
})).OnUIThread();
updateEvent.AddEventHandler(target, handler);
context.Disposing += (s, e) => updateEvent.RemoveEventHandler(target, handler);
context.Message.Detaching += (s, e) => updateEvent.RemoveEventHandler(target, handler);
}
context.CanExecute = () => (bool)guard.Invoke(context.Target, MessageBinder.DetermineParameters(context, guard.GetParameters()));
}
}
}
/// <summary>
/// Tries to find the guard method.
/// </summary>
/// <param name="context">The context.</param>
/// <returns>The guard method.</returns>
private static MethodInfo TryFindGuardMethod(ActionExecutionContext context)
{
var name = string.Format("Can{0}", context.Method.Name);
var method = context.Target.GetType().GetMethod(name);
if (method == null)
return null;
if (method.ContainsGenericParameters)
return null;
if (typeof(bool) != method.ReturnType)
return null;
var methodParameters = method.GetParameters();
var contextMethodParameters = context.Method.GetParameters();
if (methodParameters.Length == 0)
return method;
if (methodParameters.Length != contextMethodParameters.Length)
return null;
return methodParameters.Zip(contextMethodParameters, (x, y) => x.ParameterType == y.ParameterType).Any(x => !x) ? null : method;
}
/// <summary>
/// Enables support for action guard methods re-evaluation, through a specific event naming convention.
/// </summary>
public static void EnableActionGuardMethodReEvaluateSupport()
{
ActionMessage.PrepareContext = PrepareContext;
}
#endregion
}
}
```
You can download a working sample [here](http://www.mediafire.com/?irqiiq9bvbn41x4).
Comments: Using PropertyChanged notifications can lead to unnecessary work from the UI engine, since such notifications are monitored to update binding on the UI, potentially triggering measure/arrange/render passes. In my opinion, it is better to let PropertyChanged notifications out of the picture, since they have specific implications. Regarding Foody, I don't really knew the project until now, but as far as I can see, it is something like PostSharp or projects alike (I could be wrong, but since it embeds a MSBuild task...). If I am correct, this kind of approach can fail when obfuscation is used, if generated code still pushes hard-coded strings into INP notifications. Using expressions (resolved at runtime) instead, avoids this (and that's why I think it's a better way to handle such notifications). The real issue is with INPC design itself, I am afraid... Regarding collections, you are right: the default CM implementation only reacts to updates to parameter values (i.e. whenever the Parameter.Value property changes), but in certain situations the developer would prefer that the avilability is triggered if a collection used as an action parameter changes. I faced such an issue, and I could solve the problem extending the Parameter class to provide such functionality: ``` C# namespace Caliburn.Micro.Sample { #region Namespaces using System; using System.Collections.Specialized; using System.Reflection; using System.Windows; using Caliburn.Micro; #endregion /// <summary> /// Class used to define an advanced action message <see cref="Parameter" />, able to react to collection changes. /// </summary> public class AdvancedParameter : Parameter, IWeakEventListener { /// <summary> /// Initializes the <see cref="AdvancedParameter" /> class. /// </summary> static AdvancedParameter() { ValueProperty.OverrideMetadata(typeof(AdvancedParameter), new PropertyMetadata(OnValuePropertyChanged)); } #region Static Methods /// <summary> /// Called when the value property changes. /// </summary> /// <param name="d">The dependency object.</param> /// <param name="e"> /// The <see cref="System.Windows.DependencyPropertyChangedEventArgs" /> instance containing the event data. /// </param> private static void OnValuePropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) { var parameter = (AdvancedParameter)d; var oldValue = e.OldValue as INotifyCollectionChanged; if (oldValue != null) CollectionChangedEventManager.RemoveListener(oldValue, parameter); var newValue = e.NewValue as INotifyCollectionChanged; if (newValue != null) CollectionChangedEventManager.AddListener(newValue, parameter); var owner = parameter.GetOwner(); if (owner != null) owner.UpdateAvailability(); } #endregion #region IWeakEventListener Members /// <summary> /// Receives events from the centralized event manager. /// </summary> /// <param name="managerType"> /// The type of the <see cref="T:System.Windows.WeakEventManager" /> calling this method. /// </param> /// <param name="sender">Object that originated the event.</param> /// <param name="e">Event data.</param> /// <returns> /// true if the listener handled the event. It is considered an error by the /// <see /// cref="T:System.Windows.WeakEventManager" /> /// handling in WPF to register a listener for an event that the listener does not handle. Regardless, the method /// should return false if it receives an event that it does not recognize or handle. /// </returns> bool IWeakEventListener.ReceiveWeakEvent(Type managerType, object sender, EventArgs e) { if (managerType == typeof(CollectionChangedEventManager)) { var owner = GetOwner(); if (owner != null) owner.UpdateAvailability(); return true; } return false; } #endregion /// <summary> /// Gets the action message owner. /// </summary> /// <returns>The action message owner.</returns> private ActionMessage GetOwner() { return (ActionMessage)typeof(Parameter).GetProperty("Owner", BindingFlags.Instance | BindingFlags.NonPublic) .GetValue(this, null); } } } ``` (Note: the reflection used to get the Parameter Owner will not be necessary with CM 2.0, since the accessibility has been changed to protected in the latest code-base). In conjuntion with some other extensions, I am able to use a binding in short syntax, and write something like this ``` XML <Button Message.Attach="[Event Click] = [Action AddItems({Binding ElementName=someListBox, Path=SelectedItems})]"/> ``` instead of using the long syntax ``` XML <Button> <i:Interation.Triggers> <i:EventTrigger EventName="Click"> <cal:ActionMessage MethodName="AddItems"> <ext:AdvancedParameter Value="{Binding ElementName=someListBox, Path=SelectedItems}"/> </cal:ActionMessage> </i:EventTrigger> </i:Interation.Triggers> </Button> ``` The above AdvancedParameter class will work even in your case. Note that the above class does not cover all the cases where action guard re-evaluation is needed, since it only covers updates from the parameter point of view when a collection is used, while action method re-evaluation can be triggered on internal state changes.
On the one hand something like this could be integrated into Caliburn.Micro proper, on the other hand it could make more sense for the original author to package it up as an recipe.
Thoughts?
Every now and then, there is a new user that asks how to trigger availability update for action guards implemented as methods. I am aware that such methods are re-evaluated every time a parameter changes, but there are some cases where the evaluation of a guard depends on both the parameters and the internal state of the class providing the action. In such a scenario, it can be useful to have a way to forcefully request an availability update on the action.
I decided to provide a possible solution, involving a simple naming convention and the use of specific events: consider and action called 'Execute(...)' and the associated method guard 'CanExecute(...)'; my idea is to modify the PrepareContext implementation to check for the existence of a specific event, called 'ReEvaluateCanExecute' and, if available, attach to it and invoke UpdateAvailability whenever the event is invoked.
Since PrepareContext is an extensibility point, this feature can be easily added, without modifying the current CM code base.
The actual implementation is provided below:
``` C#
namespace ActionGuardSample
{
#region Namespaces
using System;
using System.ComponentModel;
using System.Linq;
using System.Reflection;
using Caliburn.Micro;
using Action = System.Action;
#endregion
/// <summary>
/// Static class used to provide Caliburn Micro extensions.
/// </summary>
public static class CaliburnMicroExtensions
{
#region Static Methods
/// <summary>
/// Prepares the context.
/// </summary>
/// <param name="context">The context.</param>
private static void PrepareContext(ActionExecutionContext context)
{
ActionMessage.SetMethodBinding(context);
if (context.Target != null && context.Method != null)
{
var targetType = context.Target.GetType();
var guardName = string.Format("Can{0}", context.Method.Name);
var guard = TryFindGuardMethod(context);
if (guard == null)
{
var inpc = context.Target as INotifyPropertyChanged;
if (inpc == null)
return;
guard = targetType.GetMethod(string.Format("get_{0}", guardName));
if (guard == null)
return;
var handler = (PropertyChangedEventHandler)null;
handler = ((s, e) =>
{
if (string.IsNullOrEmpty(e.PropertyName) || e.PropertyName == guardName)
{
((Action)(() =>
{
var message = context.Message;
if (message == null)
inpc.PropertyChanged -= handler;
else
message.UpdateAvailability();
})).OnUIThread();
}
});
inpc.PropertyChanged += handler;
context.Disposing += (s, e) => inpc.PropertyChanged -= handler;
context.Message.Detaching += (s, e) => inpc.PropertyChanged -= handler;
context.CanExecute = () => (bool)guard.Invoke(context.Target, MessageBinder.DetermineParameters(context, guard.GetParameters()));
}
else
{
var updateEventName = string.Format("ReEvaluate{0}", guardName);
var updateEvent = targetType.GetEvent(updateEventName);
if (updateEvent != null)
{
var target = context.Target;
EventHandler handler = null;
handler = (s, e) => ((Action)(() =>
{
var message = context.Message;
if (message == null)
updateEvent.RemoveEventHandler(target, handler);
else
message.UpdateAvailability();
})).OnUIThread();
updateEvent.AddEventHandler(target, handler);
context.Disposing += (s, e) => updateEvent.RemoveEventHandler(target, handler);
context.Message.Detaching += (s, e) => updateEvent.RemoveEventHandler(target, handler);
}
context.CanExecute = () => (bool)guard.Invoke(context.Target, MessageBinder.DetermineParameters(context, guard.GetParameters()));
}
}
}
/// <summary>
/// Tries to find the guard method.
/// </summary>
/// <param name="context">The context.</param>
/// <returns>The guard method.</returns>
private static MethodInfo TryFindGuardMethod(ActionExecutionContext context)
{
var name = string.Format("Can{0}", context.Method.Name);
var method = context.Target.GetType().GetMethod(name);
if (method == null)
return null;
if (method.ContainsGenericParameters)
return null;
if (typeof(bool) != method.ReturnType)
return null;
var methodParameters = method.GetParameters();
var contextMethodParameters = context.Method.GetParameters();
if (methodParameters.Length == 0)
return method;
if (methodParameters.Length != contextMethodParameters.Length)
return null;
return methodParameters.Zip(contextMethodParameters, (x, y) => x.ParameterType == y.ParameterType).Any(x => !x) ? null : method;
}
/// <summary>
/// Enables support for action guard methods re-evaluation, through a specific event naming convention.
/// </summary>
public static void EnableActionGuardMethodReEvaluateSupport()
{
ActionMessage.PrepareContext = PrepareContext;
}
#endregion
}
}
```
You can download a working sample [here](http://www.mediafire.com/?irqiiq9bvbn41x4).
Comments: Using PropertyChanged notifications can lead to unnecessary work from the UI engine, since such notifications are monitored to update binding on the UI, potentially triggering measure/arrange/render passes. In my opinion, it is better to let PropertyChanged notifications out of the picture, since they have specific implications. Regarding Foody, I don't really knew the project until now, but as far as I can see, it is something like PostSharp or projects alike (I could be wrong, but since it embeds a MSBuild task...). If I am correct, this kind of approach can fail when obfuscation is used, if generated code still pushes hard-coded strings into INP notifications. Using expressions (resolved at runtime) instead, avoids this (and that's why I think it's a better way to handle such notifications). The real issue is with INPC design itself, I am afraid... Regarding collections, you are right: the default CM implementation only reacts to updates to parameter values (i.e. whenever the Parameter.Value property changes), but in certain situations the developer would prefer that the avilability is triggered if a collection used as an action parameter changes. I faced such an issue, and I could solve the problem extending the Parameter class to provide such functionality: ``` C# namespace Caliburn.Micro.Sample { #region Namespaces using System; using System.Collections.Specialized; using System.Reflection; using System.Windows; using Caliburn.Micro; #endregion /// <summary> /// Class used to define an advanced action message <see cref="Parameter" />, able to react to collection changes. /// </summary> public class AdvancedParameter : Parameter, IWeakEventListener { /// <summary> /// Initializes the <see cref="AdvancedParameter" /> class. /// </summary> static AdvancedParameter() { ValueProperty.OverrideMetadata(typeof(AdvancedParameter), new PropertyMetadata(OnValuePropertyChanged)); } #region Static Methods /// <summary> /// Called when the value property changes. /// </summary> /// <param name="d">The dependency object.</param> /// <param name="e"> /// The <see cref="System.Windows.DependencyPropertyChangedEventArgs" /> instance containing the event data. /// </param> private static void OnValuePropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) { var parameter = (AdvancedParameter)d; var oldValue = e.OldValue as INotifyCollectionChanged; if (oldValue != null) CollectionChangedEventManager.RemoveListener(oldValue, parameter); var newValue = e.NewValue as INotifyCollectionChanged; if (newValue != null) CollectionChangedEventManager.AddListener(newValue, parameter); var owner = parameter.GetOwner(); if (owner != null) owner.UpdateAvailability(); } #endregion #region IWeakEventListener Members /// <summary> /// Receives events from the centralized event manager. /// </summary> /// <param name="managerType"> /// The type of the <see cref="T:System.Windows.WeakEventManager" /> calling this method. /// </param> /// <param name="sender">Object that originated the event.</param> /// <param name="e">Event data.</param> /// <returns> /// true if the listener handled the event. It is considered an error by the /// <see /// cref="T:System.Windows.WeakEventManager" /> /// handling in WPF to register a listener for an event that the listener does not handle. Regardless, the method /// should return false if it receives an event that it does not recognize or handle. /// </returns> bool IWeakEventListener.ReceiveWeakEvent(Type managerType, object sender, EventArgs e) { if (managerType == typeof(CollectionChangedEventManager)) { var owner = GetOwner(); if (owner != null) owner.UpdateAvailability(); return true; } return false; } #endregion /// <summary> /// Gets the action message owner. /// </summary> /// <returns>The action message owner.</returns> private ActionMessage GetOwner() { return (ActionMessage)typeof(Parameter).GetProperty("Owner", BindingFlags.Instance | BindingFlags.NonPublic) .GetValue(this, null); } } } ``` (Note: the reflection used to get the Parameter Owner will not be necessary with CM 2.0, since the accessibility has been changed to protected in the latest code-base). In conjuntion with some other extensions, I am able to use a binding in short syntax, and write something like this ``` XML <Button Message.Attach="[Event Click] = [Action AddItems({Binding ElementName=someListBox, Path=SelectedItems})]"/> ``` instead of using the long syntax ``` XML <Button> <i:Interation.Triggers> <i:EventTrigger EventName="Click"> <cal:ActionMessage MethodName="AddItems"> <ext:AdvancedParameter Value="{Binding ElementName=someListBox, Path=SelectedItems}"/> </cal:ActionMessage> </i:EventTrigger> </i:Interation.Triggers> </Button> ``` The above AdvancedParameter class will work even in your case. Note that the above class does not cover all the cases where action guard re-evaluation is needed, since it only covers updates from the parameter point of view when a collection is used, while action method re-evaluation can be triggered on internal state changes.
↧
New Post: Error Hosting WindowsFormsHost in Caliburn micro app
The inner exception says the following "{'Class not registered (Exception from HRESULT: 0x80040154 (REGDB_E_CLASSNOTREF))'}"
If I run the app in Debug mode everything works fine but when I select Release it shows this error.
If I run the app in Debug mode everything works fine but when I select Release it shows this error.
↧
New Post: Error Hosting WindowsFormsHost in Caliburn micro app
It seems the problem lies in the PDFViewer component (it should be a COM exception).
Are you sure the target platform is the same in Debug and Release? I have checked for a similar error when dealing with a PdfViewer (or alike) class, and I found this article, stating that using the approach described in the article works only if the platform is x86, since the pdf viewer component cannot work in x64 (which is equivalent to AnyCPU on an x64 system).
Are you sure the target platform is the same in Debug and Release? I have checked for a similar error when dealing with a PdfViewer (or alike) class, and I found this article, stating that using the approach described in the article works only if the platform is x86, since the pdf viewer component cannot work in x64 (which is equivalent to AnyCPU on an x64 system).
↧
↧
New Post: window manager and multiple UI threads
thanks for your response. i'm a bit worried about dispatcher switching as i need constant UI updates on the main thread as there is real time animations going on all the time
↧
New Post: Error Hosting WindowsFormsHost in Caliburn micro app
That did the trick.
Thanks
Thanks
↧
New Post: ActivateItem doesn't seem to work with WPF Frame
Trying to send a ViewModel to a WPF Frame doesn't work. If I replace the frame with ContentControl works fine.
I found a link where someone talks about how to fix this, but it means a modification to View.cs and I'd rather not modify the framework; it would cause a number of issues when my project moves to a different group for future maintenance and they didn't realize the framework was modified.
http://blog.davidsandor.com/post/2013/07/17/Using-Caliburn-Micro-with-WPF-Frame-for-navigation.aspx
Is there another work around or maybe a better way to do this?
I found a link where someone talks about how to fix this, but it means a modification to View.cs and I'd rather not modify the framework; it would cause a number of issues when my project moves to a different group for future maintenance and they didn't realize the framework was modified.
http://blog.davidsandor.com/post/2013/07/17/Using-Caliburn-Micro-with-WPF-Frame-for-navigation.aspx
Is there another work around or maybe a better way to do this?
↧
New Post: window manager and multiple UI threads
I have never used WPF for 3D visualization, but since premature optimization is the source of all evil, I would still try with the freezing/cloning approach, and measure performances. :)
↧
↧
New Post: ActivateItem doesn't seem to work with WPF Frame
I changed my logic to the following to get this working the way a Navigation Frame would without using a Navigation Frame.
I removed the Frame and ContentPresenter and replaced them with DockPanel and ContentControl.
I then implemented a Conductor in my Main ViewModel to manage and own any open screens. The Main ViewModel/View is always active and acts like a frame with chrome elements.
I then subscribed to the EventAggregator in my Main ViewModel so any child ViewModel can call the Main ViewModel using a Message class and the Main ViewModel will handle the showing and closing of Views to the ContentControl using the Conductor.
I'm guessing this is similar to the way the BootStrapper works.
I'm new to Caliburn and MVVM so this a very different way of thinking. Hope this helps other avoid the Frame Navigation trap with MVVM.
I removed the Frame and ContentPresenter and replaced them with DockPanel and ContentControl.
I then implemented a Conductor in my Main ViewModel to manage and own any open screens. The Main ViewModel/View is always active and acts like a frame with chrome elements.
I then subscribed to the EventAggregator in my Main ViewModel so any child ViewModel can call the Main ViewModel using a Message class and the Main ViewModel will handle the showing and closing of Views to the ContentControl using the Conductor.
I'm guessing this is similar to the way the BootStrapper works.
I'm new to Caliburn and MVVM so this a very different way of thinking. Hope this helps other avoid the Frame Navigation trap with MVVM.
↧
New Post: updating ToggleButton IsEnabled property throws exception
hi,
I've created a simple tester where i use a button to enable/disable a ToggleButton
when the ToggleButton control does not contain anything - all works properly
however , adding sub controls to it (in our case i just added a StackPanel)- An exception is raised:
"Value does not fall within the expected range" - right after NotifyOfPropertyChange() is called
here is the problematic view i'm using:
private bool _hasvalue;
thanks
ofer
I've created a simple tester where i use a button to enable/disable a ToggleButton
when the ToggleButton control does not contain anything - all works properly
however , adding sub controls to it (in our case i just added a StackPanel)- An exception is raised:
"Value does not fall within the expected range" - right after NotifyOfPropertyChange() is called
here is the problematic view i'm using:
<StackPanel>
<ToggleButton x:Name="SayHello" Grid.Column="1" IsEnabled="{Binding HasValue}" Height="190">
<StackPanel x:Name="sp"> </StackPanel>
</ToggleButton>
<Button x:Name="Click"></Button>
</StackPanel>
the view model:private bool _hasvalue;
public bool HasValue
{
get { return _hasvalue; }
set
{
_hasvalue = value;
NotifyOfPropertyChange(() => HasValue);
}
}
public void Click()
{
HasValue = !HasValue;
}
any way to workaround that one? - the platforms is WP8thanks
ofer
↧
New Post: updating ToggleButton IsEnabled property throws exception
You do realize that you don't have to create a separate binding for that IsEnabled property right?
CanSayHello a bool property is looked for as part of the CM convention in the viewmodel. I suspect that as a result of the convention that it's looking for the Guard of SayHello (CanSayHello) and throwing a fit, that you bound IsEnabled and dying, I suggest a change in the naming of your property to CanSayHello and don't bind it to IsEnabled.
change HasValue name to CanSayHello....
CanSayHello a bool property is looked for as part of the CM convention in the viewmodel. I suspect that as a result of the convention that it's looking for the Guard of SayHello (CanSayHello) and throwing a fit, that you bound IsEnabled and dying, I suggest a change in the naming of your property to CanSayHello and don't bind it to IsEnabled.
change HasValue name to CanSayHello....
↧