I have been working on a WPF application, and my application freezes as I Navigate from one window to another, The first window is for Login and the second window is the main window where work is carried out (the application is a form based application where Data is Written to and from a Database like MySQL)
2nd Window Operations
In the second window, I have created a Menu by placing Icons in a List and then Handling their click events to navigate to a page
These Pages are not the UI Element 'Page' but are Usercontrols I refer to them by Pages for Simplicity, and these usercontrols are added to the grid by grid.children.Add(UsercontrolName);. . . . . . This part of adding usercontrols as you can see is done in code behind(C#) and not by XAML
Click Event Handling
All i do is I simply shift the visibilty of a Usercontrol, so for example an icon that is related to a say Usercontrol A, that usercontrols visibity is set to visible and all other usercontrols visibilty is set to Collapsed, by default all usercontrols Visibilty is set to Collapsed
The Problem
What I do not Understand is what is causing this Lag or Freeze or even how to find or figure this out, I understand that WPF is an STA and UI elements such as a Grid/usercontrols should be run on the main thread , so if we Used Dispatcher to resume to the Main thread the UI wont freeze but it would Still take time to load, and I want to stop this delay
Although Contradictory I still think its the Adding of Usercontrols to the Grid is causing slow speeds, bcz these Usercontrols have numerous UI elements that I am using from a library called MaterialDesigninXAML, its a form based application so have like 8 Usercontrols all of them with textboxes and Imageboxes and buttons etc, and adding these Usercontrols at once is causing the Overhead
And I am stuck at this Delay / Freeze of the UI
The code below is a ditto example of my original code, I posted the example bcz my code is lengthier with the same problem
this is the part of the code that lags
Dispatcher.InvokeAsync(() =>
{
UserControl usc;
usc = new Y1();
usc.Tag = "Memeber";
no.Children.Add(usc);
Y4 usc2 = new Y4();
usc2.Tag = "CheckBoxList";
no.Children.Add(usc2);
Y5 usc3 = new Y5();
usc3.Tag = "Reports";
no.Children.Add(usc3);
ShowUserContro("Memeber");
}
);
private void ShowUserContro(string v)
{
foreach (UIElement item in no.Children)
{
if (item is UserControl)
{
UserControl x = (UserControl)item;
if (x.Tag != null)
{
if (x.Tag.ToString().ToUpper() == v.ToUpper())
{
x.Visibility = Visibility.Visible;
}
else
{
x.Visibility = Visibility.Collapsed;
}
}
}
}
}
private void ListViewMenu_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
ShowUserContro((((ListViewItem)((ListView)sender).SelectedItem).Name));
}
Related
I got a small program which uses 2 transparent windows.
To position them i added a small colored label.
I got this on both transparent windows.
Transparent window1 has 2 buttons increase and decrease opacity.
This button works for transparent window1 but not for transparent windows2.
private void BtnIncreaseOpacity_Click(object sender, RoutedEventArgs e)
{
lblDrag.Opacity = 100;
win2.lblDrag2.Opacity = 100;
}
In the Public partial class
TrackerMessage win2 = new TrackerMessage();
The code is accepted, but it does not work.
So i am pretty sure this is doing something different then i think.
The other problem is similar.
the transparent windows2(win2) needs to make its labels visible when a timer on transparent window1 reaches 0.
But thats more of the same problem, since right now you cannot access anything from window1 on window2
So the question is, what am i doing wrong.
Really, both Opacity properties should be bound to a view model and then the button's command modifies the backing properties (allowing the UI to update).
That said, at the very least you should have each window handling its own UI (and I suspect that is the problem). Instead of setting the property directly for win2, have it call a function:
win2.SetOpacity(100);
Where SetOpacity looks like:
public void SetOpacity(int newValue)
{
lblDrag2.Opacity = newValue;
}
You may also need to do a Dispatcher.BeginInvoke (since this is being called from the other window's UI thread). In that case, the function is:
public void SetOpacity(int newValue)
{
Dispatcher.BeginInvoke(new Action(() =>
{
lblDrag2.Opacity = newValue;
}));
}
Let me know if I can clarify anything!
To preface this question, I am working on coding the back end of an application whose UI was put together by someone else (I believe using Blend). The application consists of a series of "Screens," whose root element in XAML is "UserControl". There is no use of the "Window" tag anywhere in the source.
What I want to do is remove the Windows border that is added to the outside edge of the application when I run the program. The border currently consists of forward/backward buttons like a web browser, and an X button to close.
All I can find from searches are instructions to add
WindowStyle="None"
to the
<Window>
element. But of course, I don't have one of those, and WindowStyle is not a property of UserControl. Anyone know how to accomplish this with UserControl root elements?
Edit: The StartupUri for the application is
this.StartupUri = new Uri(#"pack://application:,,,/WpfPrototype1.Screens;Component/Screen_1.xaml");
the file it points to does not have a Window tag.
Based on the comments above it seems your MainWindow is created dynamically somewhere, however you can use the Application class to get the applications MainWindow.
var mainWindow = Application.Current.MainWindow;
And you can then set your border style from there
Example:
private void RemoveBorder()
{
var mainWindow = Application.Current.MainWindow;
if (mainWindow != null)//should never be
{
mainWindow.WindowStyle = System.Windows.WindowStyle.None; // removes top bar (icon, title, close buttons etc)
mainWindow.AllowsTransparency = true; //removes the border around the outside
}
}
I want to set the focus to a control within an application without giving focus to the whole application.
For example: Click a button which takes a while to load a screen, when the screen is loaded set the focus on one of the controls. In the meantime I have gone to a different application to do something and the focus returns to the previous application.
This happens when I use Keyboard focus or Logical focus.
Is there any way to stop this happening?
Here is the code:
private void SetFocusInternal()
{
// Focus the first control we find with the 'PositionCursor' indicator expression
FrameworkElement controlToFocus = GetFirstRequiresFocusControl();
// Give focus back to the control which last had it (if any)
if (controlToFocus == null)
controlToFocus = GetLastFocusedControl();
// Just focus the first thing we can find
if (controlToFocus == null)
controlToFocus = GetFirstFocusableControl();
// Using any of the following goes wrong!!
controlToFocus.Focus();
Keyboard.Focus(controlToFocus);
FocusManager.SetFocusedElement(FocusManager.GetFocusScope(this), controlToFocus);
}
I am having a WinForms control, inside that I have a TableLayoutPanel which holds multiple ElementHosts and each ElementHost contains a WPF control.
Everything works fine except when the size of controls is bigger then window and ScrollBar is there; when I scroll down, the controls get rendered distorted, like this -
On maximizing the window or re-sizing it, controls render properly
(reducing the size such that controls go out of visible area and then increase the size again to bring them back in visible area)
This doesn't happen with WinForms control in the same window just the WPF ones; any idea why this is happening and any solution for this?
this.Loaded += delegate
{
var source = PresentationSource.FromVisual(this);
var hwndTarget = source.CompositionTarget as HwndTarget;
if (hwndTarget != null)
{
hwndTarget.RenderMode = RenderMode.SoftwareOnly;
}
};
Try using that in the wpf control you are hosting. This is a known rendering issue of the the wpf controls that are hosted in win forms. Changing the rendering mode to software only will solve the problem.
I had a similar problem and solved forcing a refresh of the ElmenetHost in the scroll event of the TableLayoutPanel
Ok, this is gonna sound like total B.S. but it worked for me: in the Load event of your form, resize the form.
public class MyForm : Form
{
public MyForm()
{
Load += (o, e) => { Width -=1; Width +=1; };
}
}
After the form has been resized, I could not force a display issue.
My application can navigate to 3 different pages that all are being displayed in 1 window (one at a time) . All the pages that get displayed in the same window are user controls.
Whenever i click button "A" a new button gets created and added to a stackpanel. So basically if i press 5 times i get 5 buttons nicely placed next to each other.
The code below navigates the screen from page B back to A (assuming i am already on page B), here i call up a method that iterates trough the list of saved buttons.
To make it short i wish to save the items created in a list or something else so when this window gets loaded again i can simply load the values (buttons) back in.
Page B:
private void btnNoProduction_Click(object sender, RoutedEventArgs e)
{
MainWindow main = new MainWindow();
Switcher.Switch(main);
main.reloadDynamicRegistrationContent();
}
Page A (mainwindow) where i iterate over the list with the saved buttons.
public void reloadDynamicRegistrationContent()
{
for (int i = 0; i < GlobalVar._listReg.Count; i++)
{
spHorizontal.Children.Add(GlobalVar._listReg[i]); //ERROR Specified Element is already the logical.....
}
}
I need some sort of way to save these buttons (List but i keep getting the error Specified element is already the logical child of another element. Disconnect it first. wpf.
It fails when i try to access the list from the static class.
Code to create a button dynamically:
private void btnTestRegistration_Click(object sender, RoutedEventArgs e)
{
Button newBtn = new Button();
newBtn.Name = "btnRegistration" + registrationCount.ToString();
newBtn.Width = 151;
newBtn.Height = 73;
newBtn.Click += new RoutedEventHandler(this.newBtn_Click);
Thickness margin = newBtn.Margin;
margin.Left = 10;
margin.Right = 5;
newBtn.Margin = margin;
Style style = this.FindResource("ButtonStyleRegistration") as Style;
newBtn.Style = style;
//force build template
newBtn.ApplyTemplate();
var tb = VisualTreeNavigator.FindVisualChild<TextBlock>(newBtn, "tbRegistration1");
tb.Text = "text cause 1 " + registrationCount.ToString();
var tb2 = VisualTreeNavigator.FindVisualChild<TextBlock>(newBtn, "tbRegistration2");
tb2.Text = "text cause 2 " + registrationCount.ToString();
spHorizontal.Children.Add(newBtn);
GlobalVar.AddButtonToList(newBtn);
registrationCount++;
}
So far everything gets added properly but i am unable to save the bunch of buttons that got created whenever i wish to return to this screen later on.
GlobalVar is a static class where i have a list. Here i attempt to save the contents of all the buttons that are being created in a list.
public class GlobalVar
{
public static List<Button> _listReg = new List<Button>();
public static void AddButtonToList(Button b)
{
_listReg.Add(b);
}
}
In WPF each UI element can participate only once in any logical tree. You cannot have a <Button> element as a child (Child property, element in Children, Content property etc.) more than once.
It appears that MainWindow hasn't been disposed. Even if you are disposing it (i.e. MainWindow goes out of scope, and you close it) - which I'm not sure you do from your code - it isn't necessarily disposed as the garbage collection doesn't necessarily dispose the elements immediatley. There is also a possibility that the buttons keeps reference to their parent window (the spHorizontal, and eventually all the way to MainWindow) and since GlobalVar is kept alive - the MainWindow is never being disposed at all, and you actually have a leak here.
If you aren't dismissing the main window at all, and simply trying to have multiple copies of the MainWindow running simultanously then what you are trying to do is impossible. You'll have to serialize the list of buttons somehow (basically, the text you put on the Text Boxes), and then create new buttons with the same text.
If you are dismissing the MainWindow, then before closing the Window make sure to remove the list of buttons from spHorizontal, using spHorizontal.Children.Remove
Saying all that, your program has numerous opportunities for improvements. Specifically - why not just hiding the main window (this.IsVisible=false), and then showing it again when necessary? Or, why wouldn't you store spHorizontal in your GlobalVar singleton (after removing it from the tree).
Also, you'll be much better off having all the properties set in btnTestRegistration_Click method part of the Style which you apply to the button. I'm not a anti code-behind fanatic, but this is clearly a place where you should use XAML.
Heck, if that was my code, I would just had an ObservableCollection with list of items (each item represent a button), then a <ItemsControl> bound to the collection, and setting ItemsPanelTemplate to be a StackPanel.
<ItemsControl ItemsSource="...">
<!-- Items Source above should point to the list of logical items representing the buttons. -->
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<!-- this is the spHorizontal that you have -->
<StackPanel Orientation="Vertical" />
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<ItemsControl.ItemTemplate>
<DataTemplate>
<!-- this is a template for the button: -->
<Button ... />
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>