this is my simple try-it application that create a grid with 2 rows. The 1st row's height is bound to a properties. The value I assigned to it only works at run-time. I tried to make it also work when design-time but I failed to do that (I used this thread to write my app).
Please help me to see what I miss. Thank you!
[Edit]
The reason why I do this is that I want to set dynamically the height of the top grid row, ie. Grid.Row="0", to be the title bar height. Somewhere in my app, the view loaded and overlap the title bar.
You're trying to do a very strange trick, which is not supposed to work. Try to make the following changes.
MainWindow.xaml.cs -- try to always keep you code-behind clear.
namespace WpfTryIt
{
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
}
}
}
MainWindow.xaml
<Window x:Class="WpfTryIt.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow"
xmlns:s ="clr-namespace:WpfTryIt"
>
<Window.DataContext>
<s:FakeDataContext></s:FakeDataContext>
</Window.DataContext>
<Button Content="{Binding Path=BindingHeight}"/>
</Window>
And a new separate data context class, which behave different depending on the mode:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.ComponentModel;
using System.Windows;
namespace WpfTryIt
{
public class FakeDataContext
{
public int BindingHeight
{
get
{
// Check for design mode.
if ((bool)(DesignerProperties.IsInDesignModeProperty.GetMetadata(typeof(DependencyObject)).DefaultValue))
{
//in Design mode
return 100;
}
else
{
return 200;
}
}
}
}
}
Related
Okay, i have to ask this question. I searched a lot but i have 2 problems, and i only find solutions so solfe one of it, but never both.
so what do i have:
i have a UserControl
<UserControl
x:Class="Project.UserControls.UserDetailsControl"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:prism="http://www.codeplex.com/prism"
d:DesignHeight="450"
d:DesignWidth="800"
prism:ViewModelLocator.AutoWireViewModel="True"
mc:Ignorable="d">Some Controls in here</UserControl>
as you see, i am using prism. and i use also Dependency Injection with prism.Dryloc
the Code Behind:
using Project.Assistant.Common.Models;
using Project.GraphQL.Client;
using System.Windows;
using System.Windows.Controls;
namespace Project.Assistant.UserControls;
/// <summary>
/// Interaktionslogik für UserDetailsControl.xaml
/// </summary>
public partial class UserDetailsControl : UserControl
{
public User CurrentUser { get; set; }
public static readonly DependencyProperty SomeNumberProperty= DependencyProperty.Register(nameof(CurrentUser),typeof(User),typeof(UserDetailsControl));
public UserDetailsControl()
{
InitializeComponent();
}
}
These UserControl is then used like a normal Control. And in oder to get the Data into this Control, i Bind the CurrentUser like so:
<controls:UserDetailsControl Grid.Row="1" CurrentUser="{Binding CurrentUser}" />
What do i want to do:
i want to open a new Dialog out of this UserControl.
in order to open a new dialog, i want to use the IDialogService from Prism.
But when i add this to the Contructor, it simply crashes when i want to access the Usercontrol because it cannot Inject this dependency.
problem number too:
if i would simply just use a VieweModel and ViewModelLocator.AutoWireViewModel="True"
i dont know how i could implement my DependencyProperty.
here i read stuff like: "not everything needs a view model" (would solve the DependencyProperty)
and stuff like: "use viewmodels even for Usercontrols" (would solve the dependency injection, but cause problems with DependencyProperty)
what could i do?
I have a WPF application which prints 1 to 50 numbers and both XAML and code are given below. My requirement is to read out the label values with screen reader NVDA every time when a new content is set. My question is how to achieve readout the content which changes dynamically? Could you please help me to achieve this? Thanks
My XAML is
<Window x:Class="WPFAccessibility.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:WPFAccessibility"
mc:Ignorable="d"
Title="WPFAccessibility" Height="450" Width="800">
<Grid>
<Label Name="progressLabel" FontSize="20" Margin="50,50"></Label>
</Grid>
</Window>
My code behind file is
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Threading;
namespace WPFAccessibility
{
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
var mySource = Enumerable.Range(1, 50).ToList();
Task.Factory.StartNew(() => DoOperation(mySource));
}
private void DoOperation(List<int> values)
{
foreach (var i in values)
{
Thread.Sleep(1000);
var currentProgress = i;
Dispatcher.BeginInvoke(new Action(() =>
{
Process(currentProgress);
}), DispatcherPriority.Background);
}
}
private void Process(int currentProgress)
{
progressLabel.Content = "Processing... " + currentProgress;
if (currentProgress == 50)
progressLabel.Content = "Processing completed.";
}
}
}
I should probably have this as a comment to your question but I think it might help lead you to the right answer so wanted to post as an answer instead. I understand accessibility as it relates to web applications but I don't have experience with WPF apps but perhaps this similarity will help.
With html, you can use the aria-live property on an element so that when text inside it changes, the change will be announced. You can control whether just the small snippet of text that changed is announced or if the entire element is announced.
For example:
<span aria-live="true">You have <span id="timeleft">X</span> seconds left</span>
If "timeleft" is changed to 5, the screen reader will just announce "5". But that probably won't make sense just hearing "5". You can use the aria-atomic property so that the entire text is read. ("Atomic" meaning "one unit")
<span aria-live="true" aria-atomic="true">You have <span id="timeleft">X</span> seconds left</span>
Now when X is changed to 5, the screen reader will say "You have 5 seconds left". The entire <span> element is read.
So, how does this relate to your original question? You should be able to use the automation properties to do something similar. In particular, the LiveSetting property. Even though this blog, ".NET Framework 4.7.1 Accessibility and WPF Improvements", is a year old (Sept 2017), it has some good information regarding the LiveSetting property.
I have used AutomationProperties.LiveSetting="Polite" in the Label control and in the Code section I have created AutomationPeer to raise a PropertyChanged event to UIA. This LiveSettings feature is only available .NET framework 4.7.1 and onwards.
XMAL
<Window x:Class="WPFAccessibility.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:WPFAccessibility"
mc:Ignorable="d"
Title="WPFAccessibility" Height="450" Width="800">
<Grid>
<Label Name="progressLabel" FontSize="20" Margin="50,50" AutomationProperties.LiveSetting="Polite"></Label>
</Grid>
</Window>
Code
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Threading;
namespace WPFAccessibility
{
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window
{
private static int counter = 0;
public MainWindow()
{
InitializeComponent();
var mySource = Enumerable.Range(1, 50).ToList();
Task.Factory.StartNew(() => DoOperation(mySource));
}
private void DoOperation(List<int> values)
{
foreach (var i in values)
{
Thread.Sleep(2000);
var currentProgress = i;
Dispatcher.BeginInvoke(new Action(() =>
{
Process(currentProgress);
}), DispatcherPriority.Background);
}
}
private void Process(int currentProgress)
{
progressLabel.Content = "Processing... " + currentProgress;
if (currentProgress == 50)
progressLabel.Content = "Processing completed.";
var peer = UIElementAutomationPeer.FromElement(progressLabel);
if (peer == null)
peer = UIElementAutomationPeer.CreatePeerForElement(progressLabel);
peer.RaiseAutomationEvent(AutomationEvents.LiveRegionChanged);
}
}
}
So I've been doing research on this for quite a few weeks now, and haven't really come up with an answer on why this doesn't work properly... I've even researched JumpLists to see if this was what I was looking for, but also to no avail. This problem relates to when you attempt to select 'Close All Windows' by right clicking an app's icon on the task bar...
For example, here is an EXTREMELY small and simple WPF application I wrote to demonstrate the problem I am having. Here is the app's icon in the task bar with its choices on the context menu for it...
contextmenutoolbar
I am selecting the choice 'Close all windows', for reference (the bottom one, with the X to the left of it).
This is a WPF application and here is the code for App.xaml:
<Application x:Class="CloseAllWindows.App"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
>
<Application.Resources>
</Application.Resources>
</Application>
Here is App.xaml.cs, which launches the MainWindow. It also sets the application's MainWindow property to the MainWindow that is instantiated. It also sets ShutdownMode to be only when the main window is closed... I don't want the application to still run if the main window is closed and some secondary windows are left open.
using System.Windows;
namespace CloseAllWindows
{
/// <summary>
/// Interaction logic for App.xaml
/// </summary>
public partial class App : Application
{
protected override void OnStartup(StartupEventArgs e)
{
ShutdownMode = ShutdownMode.OnMainWindowClose;
var mainWindow = new MainWindow();
Application.Current.MainWindow = mainWindow;
mainWindow.Show();
}
}
}
Here is the code for MainWindow.xaml:
<Window x:Class="CloseAllWindows.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:CloseAllWindows"
mc:Ignorable="d"
Title="MainWindow" Height="350" Width="525">
<StackPanel>
<Button Content="NewWindow" Click="ButtonBase_OnClick"></Button>
</StackPanel>
</Window>
And here is the code behind for it... which launches a secondary window when I click a button. It is setting the parent window (Owner property) to the main window, like all the examples I've seen say it should be set, and then call Show() on it.
using System;
using System.ComponentModel;
using System.Windows;
namespace CloseAllWindows
{
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
}
private void ButtonBase_OnClick(object sender, RoutedEventArgs e)
{
var childWindow = new ChildWindow {Owner = this};
childWindow.Show();
}
}
}
Here is the code for the child window, ChildWindow.xaml:
<Window x:Class="CloseAllWindows.ChildWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:CloseAllWindows"
mc:Ignorable="d"
Title="ChildWindow" Height="300" Width="300">
<Grid>
</Grid>
</Window>
And it's corresponding code behind, ChildWindow.xaml.cs:
using System;
using System.Windows;
namespace CloseAllWindows
{
/// <summary>
/// Interaction logic for ChildWindow.xaml
/// </summary>
public partial class ChildWindow : Window
{
public ChildWindow()
{
InitializeComponent();
}
}
}
As you can see, these classes do not do very much... it was the simplest example of code I could write that shows the problem I am having. So the issue is, if I select Close all windows from the task bar context menu, it never closes all the windows. Instead, it will close the one child window, and still leave the main window open. Interestingly, I hear the windows dialogue chime when I do this, almost like its getting interrupted by something, but I have no idea what.
It also appears to act very randomly... if I spawn 20 windows, it will sometimes close 6 of the windows, then all of them... sometimes it will close a few windows one by one, then close the rest... sometimes it will close all child windows and leave only the main window open. Needless to say, I am pretty baffled as to the behaviour since it doesn't seem to follow any noticeable pattern... any help greatly appreciated! And hopefully the example is good enough to explain what I am trying to get at....
Well you could add an event that will close every window the event is implanted in. try this example:
step 1: add a class to your project call it whatever you want, I called it CloseWindowListener, add this code to your class:
public static class CloseWindowListener
{
public static event EventHandler<EventArgs> ClosingWindows;
public static void CloseWindows()
{
var CWindows = ClosingWindows;
if (CWindows != null)
{
CWindows(null, EventArgs.Empty);
}
}
}
step 2: Add the event handler to the window you desire to close when it is called.
public partial class TestWindow1 : Window
{
public TestWindow1 ()
{
InitializeComponent();
CloseWindowListener.ClosingWindows += CloseWindowListener_ClosingWindows;
}
private void CloseWindowListener_ClosingWindows(object sender, EventArgs e)
{
this.Close();
}
}
step 3: simply call the event from your main window or where ever you want.
private void button_Click_1(object sender, RoutedEventArgs e)
{
CloseWindowListener.CloseWindows();
}
I see tons of questions on this topic and the answers are, in my limited C# and WPF experience, overly complex. I cannot believe that Microsoft has made it this difficult (to me ) to implement a collection bound to a Listbox that changes during runtime.
Here's the deal: I have a Listbox that contains items (list of emails, actually). What occurs is that I need the Listbox to refresh when a new email arrives or gets removed from the source Folder. Sounds easy enough, but manipulating the Observable Collection in anyway is causing the dreaded "This type of CollectionView does not support changes to its SourceCollection from a thread different from the Dispatcher thread."
So nevermind for a moment about circumventing this problem by writing dispatcher stuff. Is there some "normal" way to manipulate a collection that's NOT from another thread? -- this is what I'm confused on. Where else would I modify the collection? I'd happily place my code there if this is what's expected.
My current implementation -- which may very well be poor -- is to place the Folder.Items event handlers within the collection class itself that will then add/remove emails from the collection (i.e. itself). This ain't working and I don't really understand how else one would accomplish this.
Okay, I whipped up this code example. This is NOT my application but it pretty much represents how I'm (incorrectly) handling things...and this will throw the 'cannot update source collection thread error'. The example is broken into 3 sections, first is the XAML markup, then Main class and method and the ObservableCollection class.
<Window
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:WpfApplication1" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" mc:Ignorable="d"
x:Class="WpfApplication1.MainWindow"
x:Name="Window"
Title="MainWindow"
Width="640" Height="480">
<Grid x:Name="LayoutRoot" >
<Border BorderBrush="#FF404020" BorderThickness="5" Margin="0" Background="#FFFFFFC0" CornerRadius="25">
<ListBox x:Name="lbList" Margin="50" FontSize="21.333" DisplayMemberPath="Subject"/>
</Border>
</Grid>
</Window>
using System;
using System.Collections.Generic;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Shapes;
using System.Runtime.InteropServices;
using Microsoft.Office.Interop.Outlook;
namespace WpfApplication1
{
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window
{
public MailList ml = new MailList();
public MainWindow()
{
this.InitializeComponent();
Microsoft.Office.Interop.Outlook.Application olApp = Marshal.GetActiveObject("Outlook.Application") as Microsoft.Office.Interop.Outlook.Application;
Folder f = (Folder)olApp.Session.PickFolder(); // User picks MAPI Folder
f.Items.ItemAdd += new ItemsEvents_ItemAddEventHandler(this.UpdateListBox); //Folder.Item add event, calls UpdateListBox
foreach (object o in f.Items)
{
if (o is MailItem)
{
ml.Add((MailItem)o); //Add Mailitems to ml collection
}
}
Binding b = new Binding(); //create binding for ListBox
b.Mode = BindingMode.OneWay;
lbList.DataContext = ml;
lbList.SetBinding(ListBox.ItemsSourceProperty, b);
}
public void UpdateListBox(object o) //Add new MailItem to ml collection
{
if (o is MailItem)
{
ml.Add((MailItem)o);
}
}
}
}
using System;
using System.Collections.ObjectModel;
using System.Linq;
using System.Text;
using Microsoft.Office.Interop.Outlook;
namespace WpfApplication1
{
public class MailList : ObservableCollection<MailItem>
{
public MailList()
: base()
{
}
}
}
What is supposed to be the problem with dispatching collection changes to the UI-thread? As far as i know that is the usual way to go.
To Reproduce my case (.net 4.0)
Create a WPF Application (MainWindow.xaml)
Add a Winform user control that contains a textbox (UserConrol1.cs - Winform)
Put UserControl1 into MainWindow.xaml with windowsformshost
Add another WPF Window that contains a textbox(wpf) to project (Window1.xaml)
Create and Show Window1 after MainWindow InitializeComponent
Your project is ready,
Run Project and set textbox focused in MainWindow.xaml (that in WindowsFormsHost)
Deactivate your application by opening a window (Windows file explorer ,notepad, winamp etc.)
Try to write in textbox that in Window1 window by clicking textbox with mouse
And you will see that you can't set focus on textbox in Window1 because MainWindow Texbox( in winformshost will steal your focus on you application got activating)
Any idea?
MainWindow.xaml
<Window x:Class="WinFormsHostFocusProblem.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:WinFormsHostFocusProblem"
xmlns:my="clr-namespace:System.Windows.Forms.Integration;assembly=WindowsFormsIntegration"
Title="MainWindow" Height="350" Width="525">
<Grid>
<my:WindowsFormsHost Focusable="False" >
<local:UserControl1>
</local:UserControl1>
</my:WindowsFormsHost>
</Grid>
</Window>
MainWindow.xaml.cs
namespace WinFormsHostFocusProblem
{
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
Window1 window1 = new Window1();
window1.Show();
}
}
}
Window1.xaml
<Window x:Class="WinFormsHostFocusProblem.Window1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:WinFormsHostFocusProblem"
xmlns:my="clr-namespace:System.Windows.Forms.Integration;assembly=WindowsFormsIntegration"
SizeToContent="WidthAndHeight"
ResizeMode="NoResize"
Topmost="True"
Title="Window1" Height="300" Width="300" Background="Red">
<Grid>
<TextBox Height="25">asd</TextBox>
</Grid>
</Window>
Window1.xaml.cs
namespace WinFormsHostFocusProblem
{
public partial class Window1 : Window
{
public Window1()
{
InitializeComponent();
}
}
}
I used my MSDN support contract to get an answer to this problem. The engineer was able to repro from yunusayd's sample and confirmed it is almost certainly a bug in WindowsFormsHost.
Thanks to yunus for the minimal repro sample and Keith at Microsoft for tackling the issue and providing a workaround in less than one day.
Workaround code follows. It works by using .NET reflection to change a private variable used in WindowsFormsHost and disable the trigger for the bug. According to the engineer I worked with, this relies on WPF internals, but he spoke with product team members and it should be safe to use. There's no guarantee of lack of side effects, of course, but so far I haven't found any problems in my testing with multiple WindowsFormsHosts in multiple WPF windows (maybe nesting would be trickier). I modified the original workaround to work generically with multiple windows. You can just as easily hardcode references to specific windows and named WindowsFormsHost controls in the Application_Deactivated event and skip the whole "LastActive" scheme and extension methods.
// App.xaml.cs: you must hook up to Application.Deactivated
void Application_Deactivated(object sender, EventArgs e)
{
foreach (Window w in windows)
{
foreach (var host in UI.DependencyObjectExtension.AllLogicalChildren(w).
Where(c => c is WindowsFormsHost))
{
FIELD_FOCUSED_CHILD.SetValue(host, null);
}
}
}
public readonly static FieldInfo FIELD_FOCUSED_CHILD = typeof(System.Windows.Forms.Integration.WindowsFormsHost).
GetField("_focusedChild", BindingFlags.NonPublic | BindingFlags.Instance);
public static class DependencyObjectExtension
{
/// <summary>
/// Returns a collection of o's logical children, recursively.
/// </summary>
/// <param name="o"></param>
/// <returns></returns>
public static IEnumerable<DependencyObject> AllLogicalChildren(this DependencyObject o)
{
foreach (var child in LogicalTreeHelper.GetChildren(o))
{
if (child is DependencyObject)
{
yield return (DependencyObject)child;
if (child is DependencyObject)
{
foreach (var innerChild in AllLogicalChildren((DependencyObject)child))
{
yield return innerChild;
}
}
}
}
}
}
We had a similar problem in one of our applications and found that upgrading to .net 4.5 seems to have fixed a good portion of our application's WPF/WinForms focus issues including a similar one to this.
In addition, the _focusedChild field no longer exists in the .net 4.5 version of WindowsFormsHost