|
I am working on an application that will need to open multiple windows, each on a separate thread. I have each on a different thread because each window represents a "Ticket" which will need to get data from a server, update a server, as well as other stuff and when all were running on a single thread some of the ticket windows were lagging.
I am able to create the ticket windows and pass arguments, however as soon as I start trying to update properties on the window I get exceptions. Currently each window that needs to be created is created using this method:
Private Shared Sub CreateNewWindow(Of T As Window)(ByVal newThread As Boolean, ByVal onOpened As Action(Of T), ByVal ParamArray args() As Object)
Dim activateWindow As Action = Sub()
Dim window As T = DirectCast(Activator.CreateInstance(GetType(T), args), T)
AddHandler window.Closed, Sub(s, e)
window.Dispatcher.BeginInvokeShutdown(DispatcherPriority.Background)
End Sub
window.Show()
If onOpened IsNot Nothing Then
onOpened(window)
End If
End Sub
If newThread Then
Dim newWindowThread As New Thread(New ThreadStart(Sub()
SynchronizationContext.SetSynchronizationContext(New DispatcherSynchronizationContext(Dispatcher.CurrentDispatcher))
activateWindow()
System.Windows.Threading.Dispatcher.Run()
End Sub))
newWindowThread.SetApartmentState(ApartmentState.STA)
newWindowThread.IsBackground = True
newWindowThread.Start()
Else
activateWindow()
End If
End Sub
And the window's constructor is:
Public Sub New(properties As WindowProperties)
InitializeComponent()
_ticket = properties.Ticket
Me.Top = properties.Top
SetupWindow()
End Sub
And the SetupWindow method is:
Private Sub SetupWindow()
Try
TitleBarColor = currentSettings.DefaultTicketBrush
_stop = New ManualResetEvent(False)
Me.Name = "TicketWindow_" & Ticket.id
Me.RegisterName(Me.Name, Me)
If currentSettings.FadeInTicketWindow Then
Dim fadeInAnimation As New DoubleAnimation
With fadeInAnimation
.From = 0.0
.To = 1.0
.Duration = New Duration(TimeSpan.FromSeconds(0.75))
.AutoReverse = False
End With
fadeInStoryboard = New Storyboard
fadeInStoryboard.Children.Add(fadeInAnimation)
Storyboard.SetTargetName(fadeInAnimation, Me.Name)
Storyboard.SetTargetProperty(fadeInAnimation, New PropertyPath(Window.OpacityProperty))
fadeInStoryboard.Begin(Me)
End If
Catch ex As Exception
Dim m As String = ex.Message
End Try
End Sub
Where currentSettings is an global object which is an instance of a AppSettings object which contains some configuration data andTitleBarColor is a property of the window (which implements INotifyPropertyChanged ) used for binding:
Public Property TitleBarColor As Brush
Get
Return _titleBarColor
End Get
Private Set(value As Brush)
Try
_titleBarColor = value
RaiseEvent PropertyChanged(Me, New PropertyChangedEventArgs("TitleBarColor"))
Catch ex As Exception
Dim m As String = ex.Message
End Try
End Set
End Property
However with the code this way I get an exception in the CreateWindow method at window.show which says "Must create DependencySource on same Thread as the DependencyObject".
However If I change the TitleBarColor properties Set method to:
LTitleBar.Dispatcher.Invoke(New Action(Sub()
LTitleBar.Fill = value
End Sub))
Then the exception is caught in the property with the message "The calling thread cannot access this object because a different thread owns it."
I would appreciate any assistance in how I can update properties of a window which is on a separate thread but needs to access objects on a different thread (e.g. currentSettings ) and still have binding working. I have tried various pieces of code I have found on the web but none of them have worked for me. There was one piece of code that seems to work (no exception thrown) but the bound properties did not update when a change was made to the TitleBarColor property.
Thank you in advance for any assistance with this.
A black hole is where God tried to divide by zero.
There are 10 kinds of people in the world; those who understand binary and those who don't.
|
|
|
|
|
I am unsure whether the problem was generated from these objects, or from any other underlying objects inside your code. I remember, I once had the same problem and the Dispatcher worked for me.
But I would like to advise, that the second exception is raised when there was a resource being used and another thread attempts to use it too. In that case, it throws this exception. So, a tip might be give to you, you must always try to use the Dispose() method to dispose all of the resources and release them before closing your applications. This would minimize the second exceptions.
Or even if you don't remember calling this method on every dispose-able object. Them you might consider using such objects under a using block. Which will let the .NET take care of these resources once you're done working with them.
The sh*t I complain about
It's like there ain't a cloud in the sky and it's raining out - Eminem
~! Firewall !~
|
|
|
|
|
As discussed in your other thread, all GUI work needs to be done on the main thread. You need to restructure your code so that the *work* for each window is done in a background thread (easy with the async keyword or TPL for example) so it doesn't block the UI.
Also, bindings should generally be lazy loaded. If they are expensive or time consuming, you should make them async or background.
You will encounter endless hurdles creating GUI objects on background threads.
|
|
|
|
|
I have this enum:
public enum MyEnum
{
[Description("This is enum A")]
EnumA,
[Description("This is enum B")]
EnumB,
[Description("This is enum C")]
EnumC,
}
}
I bound it to a datagrid like this:
<Window.Resources>
<ResourceDictionary>
<ObjectDataProvider x:Key="projectTypeList"
MethodName="GetValues"
ObjectType="{x:Type enums:MyEnum}">
<ObjectDataProvider.MethodParameters>
<x:Type TypeName="enums:MyEnum"/>
</ObjectDataProvider.MethodParameters>
</ObjectDataProvider>
</ResourceDictionary>
</Window.Resources>
and then
<DataGrid Grid.Row="1">
<DataGrid.Columns>
<DataGridComboBoxColumn Header="Project Type"
ItemsSource="{Binding Source={StaticResource projectTypeList}}"
Width="150"/>
</DataGrid.Columns>
</DataGrid>
I can see the enum values in the combo. What I'd really like is to show the descriptions. Can someone show me how to do this?
Many thanks!
If it's not broken, fix it until it is
|
|
|
|
|
Something along this[^] lines should do it.
|
|
|
|
|
Hello,
i am developing a Form where the user need to drag and drop between Grid,StackPanel etc. some data you can see the code below :
<Grid x:Name="LayoutRoot">
<Grid.RowDefinitions>
<RowDefinition Height="*"/>
<RowDefinition Height="*"/>
<RowDefinition Height="*"/>
<RowDefinition Height="30"/>
</Grid.RowDefinitions>
<Grid x:Name="box1" Grid.Row="0" AllowDrop="True" Drop="box_Drop" >
<Grid x:Name="grid1" Background="Aqua" Margin="15" MouseMove="grid_MouseMove">
<Grid.RowDefinitions>
<RowDefinition Height="*" />
<RowDefinition Height="*" />
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="28*" />
<ColumnDefinition Width="445*" />
</Grid.ColumnDefinitions>
<Grid Grid.Column="0" Grid.Row="0">
<TextBlock Text="1"></TextBlock>
</Grid>
<Grid Grid.Column="0" Grid.Row="1">
<TextBlock Text="2"></TextBlock>
</Grid>
<Grid Grid.Column="0" Grid.Row="2">
<TextBlock Text="3"></TextBlock>
</Grid>
<StackPanel Name="firsts" AllowDrop="True" Drop="box_Drop_first" Grid.Row="0" Grid.Column="1" >
<StackPanel MouseMove="grid_MouseMove_first" Name="firstsrow" Margin="2" Background="Beige" Height="17"></StackPanel>
</StackPanel>
<StackPanel Name="seconds" AllowDrop="True" Grid.Row="1" Grid.Column="1" Drop="box_Drop_first" >
<StackPanel MouseMove="grid_MouseMove_first" Name="secondrow" Margin="2" Background="Gainsboro" Height="17"></StackPanel>
</StackPanel>
<StackPanel Name="thirds" AllowDrop="True" Grid.Row="2" Grid.Column="1" Drop="box_Drop_first" >
<StackPanel MouseMove="grid_MouseMove_first" Name="thirdrow" Margin="2" Background="Red" Height="17"></StackPanel>
</StackPanel>
</Grid>
</Grid>
<Grid x:Name="box2" Grid.Row="1" AllowDrop="True" Drop="box_Drop">
<Grid x:Name="grid2" Background="blue" Margin="15" MouseMove="grid_MouseMove">
<Grid.RowDefinitions>
<RowDefinition Height="*" />
<RowDefinition Height="*" />
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="28*" />
<ColumnDefinition Width="445*" />
</Grid.ColumnDefinitions>
</Grid>
</Grid>
<Grid x:Name="box3" Grid.Row="2" AllowDrop="True" Drop="box_Drop">
<TextBlock Text="3" HorizontalAlignment="Left" Width="30" Margin="10,0,0,77"></TextBlock>
<Grid x:Name="grid3" Background="green" Margin="15" MouseMove="grid_MouseMove">
</Grid>
</Grid>
</Grid>
and the code Behind :
public partial class Window1 : Window
{
public Window1()
{
InitializeComponent();
}
private void grid_MouseMove(object sender, MouseEventArgs e)
{
// Get the grid that is the source of drag
Grid selectedGrid = sender as Grid;
if (selectedGrid != null && e.LeftButton == MouseButtonState.Pressed)
{
// Add that grid as drag source and data
DragDrop.DoDragDrop(selectedGrid, selectedGrid, DragDropEffects.Move);
}
}
private void box_Drop(object sender, DragEventArgs e)
{
// Get the selected box in which the object is being dropped
Grid selectedBox = sender as Grid;
if (selectedBox != null)
{
// Get that data that is being dropped - in this case, the grid from other box
Grid droppedGrid = (Grid)e.Data.GetData(typeof(Grid));
// We need to remove the dragged grid from it's source box in order to be able to add it to selected box
Grid sourceBox = (Grid)droppedGrid.Parent;
// Remove the dropped grid from source box
sourceBox.Children.Remove(droppedGrid);
// We need to remove the other grid from the selected box in order to be able to move it to source box
// Get existing child element, the box has only one child - the grid that we need
Grid existingChild = (Grid)selectedBox.Children[0];
// Remove existing child grid from selected box
selectedBox.Children.Remove(existingChild);
// Finally, move grids to new boxes
// Move existing child grid to source box
sourceBox.Children.Add(existingChild);
// Move the dropped grid to selected box
selectedBox.Children.Add(droppedGrid);
}
}
private void box_Drop_first(object sender, DragEventArgs e)
{
StackPanel selectedBox = sender as StackPanel;
if (selectedBox != null)
{
// Get that data that is being dropped - in this case, the grid from other box
StackPanel droppedGrid = (StackPanel)e.Data.GetData(typeof(StackPanel));
// We need to remove the dragged grid from it's source box in order to be able to add it to selected box
// StackPanel sourceBox = new StackPanel();
StackPanel sourceBox = (StackPanel)droppedGrid.Parent;
// Remove the dropped grid from source box
sourceBox.Children.Remove(droppedGrid);
// We need to remove the other grid from the selected box in order to be able to move it to source box
// Get existing child element, the box has only one child - the grid that we need
StackPanel existingChild = (StackPanel)selectedBox.Children[0];
// Remove existing child grid from selected box
selectedBox.Children.Remove(existingChild);
// Finally, move grids to new boxes
// Move existing child grid to source box
sourceBox.Children.Add(existingChild);
// Move the dropped grid to selected box
selectedBox.Children.Add(droppedGrid);
}
}
private void grid_MouseMove_first(object sender, MouseEventArgs e)
{
StackPanel selectedGrid = sender as StackPanel;
if (selectedGrid != null && e.LeftButton == MouseButtonState.Pressed)
{
// Add that grid as drag source and data
DragDrop.DoDragDrop(selectedGrid, selectedGrid, DragDropEffects.Move);
}
}
}
The Grids "box1,box2,box3" are not movable instead their Childs are all movable (beacause in teh final project these will be populate with data then the user should be able to move and change the data when need) .
When i debug the project and i want move the StackPanel"firstrow,secondrow,thirdrow" between others StackPanel as"firsts,seconds.thirds" i got always an error as "Object reference not set to an instance of an object." or "Specified argument was out of the range of valid values.
Parameter name: index" then don't allow to drag drop .
Sincerely i am new of WPF then sure i done some mistakes then i ask you kindly if you have some suggestion or better idea to work out this error.
Thank you in advance for the attention.
Sincerely
|
|
|
|
|
The simple answer to this is, that some of the objects that you're trying to pass has not been initialized (or putting it simple, does not exist; is null). Try to create an instance of all of the objects, and their properties that are requried to be passed on as a parameter.
Are all of your objects initialized?
The sh*t I complain about
It's like there ain't a cloud in the sky and it's raining out - Eminem
~! Firewall !~
|
|
|
|
|
Your Code is behaving the correct way. box1,box2,box3 cannot be moved becaused you did not handle the events to move them but stackPanels which are the Children can move.
Vuyiswa Maseko,
Spoted in Daniweb-- Sorry to rant. I hate websites. They are just wierd. They don't behave like normal code.
C#/VB.NET/ASP.NET/SQL7/2000/2005/2008
http://www.vuyiswamaseko.com
vuyiswa[at]dotnetfunda.com
http://www.Dotnetfunda.com
|
|
|
|
|
In my application I have a window with a custom look and title bar. The XAML for my window is:
<Window x:Class="TicketWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="Ticket Window" Height="300" Width="300"
WindowStyle="None" ShowInTaskbar="False">
<WindowChrome.WindowChrome>
<WindowChrome CaptionHeight="{Binding ActualHeight,ElementName=titlebar}"/>
</WindowChrome.WindowChrome>
<DockPanel LastChildFill="True">
<Border Background="{DynamicResource {x:Static SystemColors.ScrollBarBrushKey}}" DockPanel.Dock="Top" Height="25" x:Name="titlebar">
<TextBlock Text="{Binding Title, RelativeSource={RelativeSource FindAncestor,AncestorType=Window},FallbackValue=Title}"
Margin="10,0,0,0"
VerticalAlignment="Center">
<TextBlock.Effect>
<DropShadowEffect Color="White" ShadowDepth="3"/>
</TextBlock.Effect>
</TextBlock>
</Border>
<Border BorderBrush="LightGray" BorderThickness="1" Padding="4">
<TextBlock><Run Text="Window content"/><InlineUIContainer>
<Button Content="Button" Width="75" Click="Button_Click"/>
</InlineUIContainer></TextBlock>
</Border>
</DockPanel>
</Window>
I would like to be able to blink the title bar under some circumstances from a second thread using a loop. For testing purposes I am using the button to start the thread to blink the title bar between green and red with a half-second delay in between the changes.
In the button's click event I create a thread and start it:
Private Sub Button_Click(sender As Object, e As RoutedEventArgs)
Try
Dim thread As New Thread(AddressOf ChangeTitleBarColor)
thread.Start()
Catch ex As Exception
Dim m As String = ex.Message
End Try
End Sub
I've only used the Dispatcher a couple of times, so to initially test the ChagneTitleBarColor method and ensure I was using the Dispatch correct I used the following code:
Private Sub ChangeTitleBarColor()
Try
titlebar.Dispatcher.Invoke(Threading.DispatcherPriority.Render, Sub()
titlebar.Background = Brushes.Green
End Sub)
Thread.Sleep(500)
titlebar.Dispatcher.Invoke(Threading.DispatcherPriority.Render, Sub()
titlebar.Background = Brushes.Red
End Sub)
Thread.Sleep(500)
Catch ex As Exception
Dim m As String = ex.Message
End Try
End Sub
And this worked; the title bar went from the default grey to green, there is a half-second delay, and then the title bar changes to red. Next I tried the following code:
Private Sub ChangeTitleBarColor()
Try
titlebar.Dispatcher.Invoke(Threading.DispatcherPriority.Render, Sub()
titlebar.Background = Brushes.Green
Thread.Sleep(500)
titlebar.Background = Brushes.Red
End Sub)
Catch ex As Exception
Dim m As String = ex.Message
End Try
End Sub
However the title bar never turns green with the above code; it goes from grey to red. So I took the the first version of the ChangeTitleBarColor and added a loop so the title bar would switch between green and red indefinitely:
Private Sub ChangeTitleBarColor()
Try
While True
titlebar.Dispatcher.Invoke(Threading.DispatcherPriority.Render, Sub()
titlebar.Background = Brushes.Green
End Sub)
Thread.Sleep(500)
titlebar.Dispatcher.Invoke(Threading.DispatcherPriority.Render, Sub()
titlebar.Background = Brushes.Red
End Sub)
Thread.Sleep(500)
End While
Catch ex As Exception
Dim m As String = ex.Message
End Try
And this works fine as well.
I even tried adding another Thread.Sleep(500) after the changing the color to red and a call to an empty action (Private EmptyDelegate As New Action(Sub()End Sub) ) using the Dispatch.Invoke before each call to the sleep method of Thread and it still didn't work.
I would appreciate it if someone could explain why if I change the title bar twice in the single invoke statement (as in the second example of the ChangeTitleBarColor below) why the color only changes a single time? Is there a simpler way to switch the title bar between two colors indefinitely from a second thread?
Thank you in advance. Any help would be greatly appreciated.
A black hole is where God tried to divide by zero.
There are 10 kinds of people in the world; those who understand binary and those who don't.
|
|
|
|
|
Hi,
I am setting the selected index of combobox in ViewModel constructor. After setting the selectedIndex I have fire the SelectionChanged event. Kindly help me.
|
|
|
|
|
With Google now having screwed Silverlight by removing support NPAPI what future does it have, if any?
Should we start looking at HTML5? Or is there something better coming?
TIA
|
|
|
|
|
That is really a question for Microsoft to answer.
|
|
|
|
|
Microsoft recommends using HTML5 for web based applications. Silverlight is purely in maintenance mode now.
|
|
|
|
|
Never used them or stumble on any custom implementation of them.
Dunno why I need them! Nor how I should write them!
Any tips or explanation please?
|
|
|
|
|
Automation Peers allow us to programatically control UI elements from outside the application (i.e., to do things like automated UI testing).
|
|
|
|
|
|
[UPDATE]
Figured it out. Was binding to the event instead of the Handler
[UPDATE]
I created a user control with this event:
public partial class AssignedEmployeesControl : _BaseUserControl
{
public static readonly RoutedEvent AssignmentRemovedEvent =
EventManager.RegisterRoutedEvent("AssignmentRemoved",
RoutingStrategy.Bubble, typeof(RoutedEventHandler),
typeof(AssignedEmployeesControl));
public event RoutedEventHandler AssignmentRemoved
{
add { AddHandler(AssignmentRemovedEvent, value); }
remove { RemoveHandler(AssignmentRemovedEvent, value); }
}
protected void OnAssignmentRemoved()
{
RaiseEvent(new RoutedEventArgs(AssignmentRemovedEvent));
}
I then add my control to a DataGrid in another control
<DataGridTemplateColumn Header="Assigned Employees"
Width="*">
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<vc:AssignedEmployeesControl EngineRef="{Binding
ElementName=employeeJobAssignmentsView, Path=EngineRef}"
AssignmentShift="{Binding Shift}">
<i:Interaction.Triggers>
<i:EventTrigger EventName="AssignmentRemovedEvent">
<i:InvokeCommandAction
Command="{Binding ElementName=employeeJobAssignmentsView,
Path=AssignmentRemovedCommand}"/>
</i:EventTrigger>
</i:Interaction.Triggers>
</vc:AssignedEmployeesControl>
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
I then have a command to catch the event:
private ICommand _AssignmentRemovedCommand;
public ICommand AssignmentRemovedCommand
{
get
{
if (_AssignmentRemovedCommand == null)
_AssignmentRemovedCommand = new RelayCommand(p =>
assignmentRemovedExecuted(), p => assignmentRemovedCanExecute());
return _AssignmentRemovedCommand;
}
}
private bool assignmentRemovedCanExecute()
{
return true;
}
private void assignmentRemovedExecuted()
{
}
When I run it, my control calls OnAssignmentRemoved, but the host control's assignmentRemovedExecuted method never fires.
I get no compilation errors or ouput methods. I get no response at all.
Can anyone see what's wrong?
Thanks
If it's not broken, fix it until it is
modified 18-Dec-14 16:01pm.
|
|
|
|
|
First the main issue:
I have a Path that I create at runtime and show it on a custom control. This part works perfect. The visual tree is simple:
Control
-Line
-Control
--Grid
---Path
UseLayoutRound=True, SnapToDevicePixels=True. Line is a 1 pixel tall horizontal line and the user can customize the vertical position.
I need to stroke the path in two different colors. One color for above the line and one color for below the line. Typical solution I see is to use a 2 color brush. However, as you might suspect, it is *EXTREMELY CRITICAL* visually that the color change happen *EXACTLY* on the horizontal line. +/- 1 pixel is not acceptable.
The problem I'm having seems to be to align the color change on the line 100% of the time. For example, if my control is 99 pixels high and the threshold is at 50%, I should have 49 + 1 + 49.
I have tried the following solutions… problems I encountered are listed as well. Any way to get this working perfectly 100% of the time?
1) Vertical LinearGradientBrush
Generally works and hits the line 100% of the time, but it doesn’t give me a hard break between the two colors, so for example black going into white will leave a gray line
2a) DrawingBrush with RectangleGeometries
2b) DrawingBrush with DrawingContext
Both of these ideas have the same problem. I can’t hit the line 100% of the time (round off errors I’m guessing…) but I’m using the same math as with #1, so…
I can get a hard color change with both these, but I get +/- 1 pixel off errors…
|
|
|
|
|
My first thought would be to draw the line twice.
Once as a TWO pixel tall line in one color,
then again as a ONE pixel tall line in the other color, overwriting half of the line.
I don't know how accurately this would work...
A positive attitude may not solve every problem, but it will annoy enough people to be worth the effort.
|
|
|
|
|
The problem seems to be that DrawingBrush has round-off errors internally or it doesn't work the same way as the LinearGradientBrush in terms of origin / relative ratios. Like I said, LinearGradientBrush hits the line consistently with my "math". DrawingBrush isn't even consistent at 50% which should not even be suspectible to round-off errors since its a whole pixel. Sometimes its 1 pixel too high, sometimes its 1 pixel too low. Also tried TransformToVisual to go from the line to the path, but TransformToVisual considers both shapes to be the same height (as the height of the control), so it just maps the points 1 to 1. Tried Math.Round() and Math.Ceiling(), etc. LOL. The line itself certainly doesn't move around, its always at the exact correct location. Tried get the rendered bounds of the path and calculating it from that, but same thing... +/- 1 issues. Also tried setting everything to absolute mode and setting the rectangles identically, nope... Maybe the LinearGradientBrush only *appears* to be working and is hiding the +/- 1 issues with the gradiented color switch.
|
|
|
|
|
I have a DataGrid with a Date column. I need to show the date as:
"Wed, 12 Dec" - Short day, day number, and short month
I've tried a bunch of options, including these[^], but I can't get it to work.
What's the correct XAML for this?
Thanks
If it's not broken, fix it until it is
|
|
|
|
|
|
Technically accurate but practically useless.
I didn't ask for the ISO standards.
What's the XAML?? I tried a bunch and it won't compile.
If it's not broken, fix it until it is
|
|
|
|
|
Kevin Marois wrote: I tried a bunch and it won't compile. Interesting, but you cannot expect people to guess what that bunch comprises.
|
|
|
|
|
Which is exactly why I provided the link to what I tried
If it's not broken, fix it until it is
|
|
|
|
|