|
I am tring to implement RaiseEvent for WindowsFormHost. It does not work either Can some body help me find out what I did wrong here:
// Create a custom routed event by first registering a RoutedEventID
// This event uses the bubbling routing strategy
public static readonly RoutedEvent WindowsFormsHostMouseDownEvent = EventManager.RegisterRoutedEvent("WindowsFormsHostMouseDown", RoutingStrategy.Bubble, typeof(RoutedEventHandler), typeof(WindowsFormsHost));
// Provide CLR accessors for the event
public event RoutedEventHandler WindowsFormsHostMouseDown
{
add { AddHandler(WindowsFormsHostMouseDownEvent, value); }
remove { RemoveHandler(WindowsFormsHostMouseDownEvent, value); }
}
private void lstBox_MouseDown(object sender, System.Windows.Forms.MouseEventArgs e)
{
RoutedEventArgs newEventArgs = new RoutedEventArgs(WindowsFormsHostMouseDownEvent, windowsFormHost);windowsFormHost.RaiseEvent(newEventArgs);
this.WindowsFormsHostMouseDown += new RoutedEventHandler(DragCanvasWindow_WindowsFormsHostMouseDown);
}
void DragCanvasWindow_WindowsFormsHostMouseDown(object sender, RoutedEventArgs e)
{
DragDrop.DoDragDrop(windowsFormHost, windowsFormHost, DragDropEffects.Move);
}
|
|
|
|
|
One would think that you would be able to add any visual element to the form and them inside the visual element events which are handling drag and drop would be sufficient to handle any element dragged and dropped onto its surface area.
This was if the element is another window you can at the very least render the target bitmap of the entire window and draw that inside the visual element. Then hooking the events in the new window to the visual element in the main window providing you a way to update them upon move or whatever other event you wanted...
|
|
|
|
|
Hi Josh,
We have a question regarding how to implement MVVM.
We have followed your article "WPF Apps With the Model-View-VieModel Design patter" to implement our prototype project.
So far we implement INotifyPropertyChanged in the viewmodel layer, we bind the viewmodel layer property with the UI control.
When the viewmodel layer property changes, we raise the OnPropertyChanged("TimeSetting "), UI control reflects the change right way.
Since the application will control a real instrument. We need propagate the change from model layer to UI layer. If model layer property changes, it will notify the viewmodel layer property and then update UI.
We implement INofityPropertyChanged in the model layer.
How do we implement Viewmodel to support this propagation?
Should we implement dependency properties in the Viewmodel layer and bind the model layer properties with Viewmodel's dependency properties? Or there is another way to do that?
We implement Viewmodel class to wrap a model class. All properties binding to UI is string properties for easy to do validation (following your article “Using ViewModel to Provide Meaningful Validation Error Messages”).
In the Model class,
public TimeSpan TimeSetting { get; set; }
In Viewmodel class,
public string TimeSetting
{ get {return timeSetText; }
set {
if (value == timeSetText)
return;
timeSetText = value;
this.OnPropertyChanged("TimeSetting");
}
}
we update model value during validaiton
string IDataErrorInfo.this[string propertyName]
{
get
{
if (propertyName == "TimeSetting")
{
string msg = this.ValidateTimeSet();
if (!string.IsNullOrEmpty(msg))
{
TimeSettingError = msg;
return msg;
}
// apply the time setting value now so that the runcondition object can also validate time vale
runConditions.TimeSetting = TimerUtility.StringToTimeSpan(timeSetText);
TimeSettingError =(runConditions as IDataErrorInfo)[propertyName];
return TimeSettingError;
}
Thanks!
|
|
|
|
|
The easiest way to do this is handle the PropertyChanged event of the Model object in the ViewModel, and switch(e.PropertyName) to raise the VM's PropertyChanged event for the corresponding bound property.
|
|
|
|
|
Josh, Thanks for the solution. It is an easy solution!
|
|
|
|
|
|
|
Attempting to use your implementation. I am afraid my requirements are making this difficult.
Couple things:
1. A CollectionViewSource and DataObjectProvider is used and the collection is populated outside the UI thread from another class. This class has the window (where we want to dnd) instance is passed to the constructor when it is instanciated so we can update the ObjectDataProvider (and others). On app start we send our an async request via this outside class, and when request is recieved via an event handler the DataObjectProvider ObjectInstance is set to the recieved data(after it is converted to the ObservableCollection of course).
2. CollectionViewSource is used as as follows:
<ObjectDataProvider x:Key="ObjectDataProviderCalls" />
<CollectionViewSource x:Key="CollectionViewSourceCalls" Source="{StaticResource ObjectDataProviderCalls}" >
<CollectionViewSource.GroupDescriptions>
<PropertyGroupDescription PropertyName="Ext" />
</CollectionViewSource.GroupDescriptions>
<CollectionViewSource.SortDescriptions>
<componentModel:SortDescription PropertyName="Id" Direction="Ascending" />
</CollectionViewSource.SortDescriptions>
</CollectionViewSource>
Here is the exact error message:
Value cannot be null.
Parameter name: data
3. I attempted to create the ListViewDragDropManager when I set the DataObjectProvider's ObjectInstance (in the external thread), but received the "..you cannot update this object from this thread". I dont have the exact message, but also tried to put the ListViewDragDropManager instanciation code w/in a method w/in the Window and used Dispatcher.Invoke to call the code but didnt work.
Not sure if I am simple doing something wrong of if we need to modify this implementation to enable it to work w/in our context. I believe this to come down to threading (what fun).
TIA,
Steve
|
|
|
|
|
Hi Josh,
Thanks for posting this as a community resource - it's greatly appreciated!
I downloaded the source recently and noticed a problem with two of the RegexValidationRule constructors. It seems that the ErrorMessage property is not being set to the value of the errorMessage constructor parameter.
The original source code looks like:
public RegexValidationRule(string regexText, string errorMessage)
: this(regexText)
{
this.RegexOptions = regexOptions;
}
public RegexValidationRule(string regexText, string errorMessage, RegexOptions regexOptions)
: this(regexText)
{
this.RegexOptions = regexOptions;
}
When they probably should be:
public RegexValidationRule(string regexText, string errorMessage)
: this(regexText)
{
this.ErrorMessage = errorMessage;
}
public RegexValidationRule(string regexText, string errorMessage, RegexOptions regexOptions)
: this(regexText, errorMessage)
{
this.RegexOptions = regexOptions;
}
I've changed the assignment in the first constructor to set the ErrorMessage property instead of RegexOptions . I've also changed the second constructor to call the this(string, string) constructor overload instead of this(string) to ensure that the properties are set correctly.
I'm guessing this was a copy and paste error that snuck past the compiler because the regexOptions constructor parameter and the regexOptions backing store field use the same name.
I suppose that's another argument in favour of the convention that backing store fields for properties should be in camel-case prefixed with an underscore and parameters should just be camel-case.
Thanks again for an excellent resource!
Cheers,
John
|
|
|
|
|
Great catch, John! I'll update the source code with your fix as soon as I get a chance. Thanks!
|
|
|
|
|
My pleasure, Josh!
BTW, can I make a suggestion? Since I've modified my copy of the source code I took the liberty of adding another property to the regex validation rule.
I've added a boolean property called InvalidOnMatch, which allows me to decide whether the matching the regex is a good thing or a bad thing. I've used this for some situations where it's easier to write the regex to find bad data than it is to find good.
So, when InvalidOnMatch is false, the rule behaves as it would normally; when the value is true then it returns a ValidationResult.IsValid = false result if the regex matches successfuly.
If you're already touching the source code, do you think it'd be a worthwhile addition?
Cheers,
John
|
|
|
|
|
Definitely! That's a great addition. Thanks for letting me know about it.
|
|
|
|
|
Again, my pleasure!
If it saves you some time, let me copy the relevant changes here (I'm presuming the latest version of the framework, thus the auto-implemented property):
public bool InvalidOnMatch { get; set; }
And in the Validate method, I've modified the lines that check the regex to be:
if (!(Regex.IsMatch(text, this.RegexText, this.RegexOptions) ^ InvalidOnMatch))
result = new ValidationResult(false, this.ErrorMessage);
I've also modified the test project to be able to muck about with testing the InvalidOnMatch property. I've added a new combo box that let's you select a validation expression to use and a checkbox to set the InvalidOnMatch property (incidentally, this gives a nice example of how to bind to a validation rule in XAML).
My changes require that you add a string property called FreeFormText to the TestData.cs file. The complete updated XAML for the RegexValidatorWindow.xaml file is:
<Window x:Class="Test.RegexValidator.RegexValidatorWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:jas="clr-namespace:WPF.JoshSmith.Controls.Validation;assembly=WPF.JoshSmith"
xmlns:local="clr-namespace:Test.RegexValidator"
Title="RegexValidator & RegexValidationRule Test" Height="341" Width="375"
FontSize="12"
>
<Window.Resources>
<!-- This validation rule is a static resource to demonstrate a technique for
binding to the properties of a regular expression -->
<jas:RegexValidationRule
x:Key="ProductCodeValidationRule"
RegexText="^[A-Z]{3}\.[0-9]{3}$"
ErrorMessage="Invalid product code. (Examples: ABC.123 xyz.789)"
RegexOptions="IgnoreCase"
/>
<!-- This style allows a validation error message to be
displayed in a TextBox's tooltip. -->
<Style TargetType="{x:Type TextBox}">
<Setter Property="Margin" Value="0,8" />
<Style.Triggers>
<Trigger Property="Validation.HasError" Value="True">
<Setter Property="ToolTip"
Value="{Binding
RelativeSource={RelativeSource Self},
Path=(Validation.Errors)[0].ErrorContent
}"/>
</Trigger>
</Style.Triggers>
</Style>
</Window.Resources>
<StackPanel Margin="4" VerticalAlignment="Center">
<TextBlock>E-mail Address:</TextBlock>
<TextBox
Text="{Binding Path=EmailAddress, UpdateSourceTrigger=PropertyChanged}"
jas:RegexValidator.RegexText="^[a-zA-Z0-9._%-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,4}$"
jas:RegexValidator.ErrorMessage="Invalid e-mail address."
/>
<!-- Sets the RegexText attached property to a static property
which returns a localized regex, for the current date format. -->
<TextBlock>Localized Date:</TextBlock>
<TextBox
Text="{Binding Path=DateString, UpdateSourceTrigger=PropertyChanged}"
jas:RegexValidator.RegexText="{x:Static local:DateFormatRegex.DateRegex}"
jas:RegexValidator.ErrorMessage="Invalid date format."
/>
<!-- Explicitly creates a RegexValidationRule in order to set the RegexOptions. -->
<TextBlock>Product Code:</TextBlock>
<TextBox>
<TextBox.Text>
<Binding Path="ProductCode" UpdateSourceTrigger="PropertyChanged">
<Binding.ValidationRules>
<jas:RegexValidationRule
RegexText="^[A-Z]{3}\.[0-9]{3}$"
ErrorMessage="Invalid product code. (Examples: ABC.123 xyz.789)"
RegexOptions="IgnoreCase"
/>
</Binding.ValidationRules>
</Binding>
</TextBox.Text>
</TextBox>
<!-- Explicitly creates a RegexValidationRule in order to set the RegexOptions. -->
<TextBlock>Dynamic Regex:</TextBlock>
<ComboBox SelectedValue="{Binding Path=RegexText, Source={StaticResource ProductCodeValidationRule}}"
IsEditable="True" SelectedValuePath="Content" SelectedIndex="0">
<ComboBoxItem>(?#IP Address)^(?!0+\.0+\.0+\.0+$)(2[0-4]\d|25[0-5]|[01]?\d\d?)\.(2[0-4]\d|25[0-5]|[01]?\d\d?)\.(2[0-4]\d|25[0-5]|[01]?\d\d?)\.(2[0-4]\d|25[0-5]|[01]?\d\d?)$</ComboBoxItem>
<ComboBoxItem>(?#UK NI Number)^[A-CEGHJ-PR-TW-Z][A-CEGHJ-NPR-TW-Z]([ ]?\d{2}){3}[ ]?[A-D]?$</ComboBoxItem>
<ComboBoxItem>(?#Variable Names)^[a-zA-Z_][a-zA-Z_0-9]*</ComboBoxItem>
<ComboBoxItem>(?#String in quotes)"[^"\\]*(\\.[^"\\]*)*"</ComboBoxItem>
<ComboBoxItem>(?#Or write your own after this comment)</ComboBoxItem>
</ComboBox>
<CheckBox IsChecked="{Binding Path=InvalidOnMatch, Source={StaticResource ProductCodeValidationRule}}" Height="16" Width="120" HorizontalAlignment="Right">Invalid on match</CheckBox>
<TextBlock>Text to validate:</TextBlock>
<TextBox>
<TextBox.Text>
<Binding Path="FreeFormText" UpdateSourceTrigger="PropertyChanged">
<Binding.ValidationRules>
<StaticResource ResourceKey="ProductCodeValidationRule"/>
</Binding.ValidationRules>
</Binding>
</TextBox.Text>
</TextBox>
</StackPanel>
</Window>
Phew! That was an awful lot of stuff for a single post! If you want me to send you a zip file with all of the modifications, just let me know and we can swap email addresses.
Cheers,
John
|
|
|
|
|
Great work on all of these classes. I was just wondering if these changes still being planned to be included when you have the time? Thanks
|
|
|
|
|
Hey Josh,
I want to thank you for all your great articles here at Codeproject. I really enjoyed reading them!!! I am studying computer science at a university in germany and am trying to learn programming in WPF. When I started to learn the WPF, I read some books but finally ended up here at Codeproject, where I studied most of your articles.
About a year ago I had to do a project at my university and got stuck while programming many times. I searched the internet for answers (google), I looked into books - but I often found nothing until I looked in your articles. After my project at the university was over, a professor asked me how to learn the WPF - and I was able to tell him the best way to get started with Windows Presentation Foundation: Just read Mr. Smith's articles !!!
So thank you once again and please keep teaching us "The WPF Way"
- Simon
|
|
|
|
|
Wow! Thanks a lot Simon. I really appreciate that.
|
|
|
|
|
Hi Josh:
i need to do a multiple-row drag and drop in a list (reorder). Can you help me?
tks
smalcain
|
|
|
|
|
Thanks Josh! I am thinking about how I can use your UIElementAdorner
|
|
|
|
|
|
Thanks Lynn. I hope you find it useful.
:josh:
My WPF Blog[ ^]
All of life is just a big rambling blog post.
|
|
|
|
|
Josh... excellent as always. I'm just starting in WPF (of course I couldn't start with just "Hello World", I had to start with a full blown lookless (ahem... sort of) custom control - good thing I keep my hair short) and your various articles have helped a lot. I can already see a few things in this library that will help with what I'm doing next. And we'll also be using the Infragistics WPF controls. Thanks, and keep up the good work!
My neglected blog: http://www.michelrenaud.com
|
|
|
|
|
Thanks a lot, Michel. I hope you end up enjoying WPF as much as I do! It's a great platform.
:josh:
My WPF Blog[ ^]
All of life is just a big rambling blog post.
|
|
|
|
|
Doesn't load into VS 2008, gives a project type not supported... nor does it try to convert it.
|
|
|
|
|
Worked for me. I'm not sure what would cause it to fail for you.
:josh:
My WPF Blog[ ^]
All of life is just a big rambling blog post.
|
|
|
|
|
Works fine here... (Downloaded latest update, July 13, 2008)
My neglected blog: http://www.michelrenaud.com
|
|
|
|