I have an issue with a WPF application that I'm writing. I have a window that I load with profile pictures for the user to choose from when setting up an account within the application. Each picture is loaded into a user control, and placed in a stackpanel, so that when the user clicks the picture, it triggers the code in the user control, and automatically sets their profile picture without any more clicking needed. This window loads on 64-bit systems just fine. However, when loading on a 32-bit system, the entire application crashes. The faulting module is wpfgfx_v0400.dll. I don't know why it's crashing. Please help.
Here's the error in the Event Viewer:
Here's the XAML on the frontend of the window in question:
<Window x:Class="RandomApplication.Windows.ChooseProfilePic"
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:RandomApplication.Windows"
mc:Ignorable="d"
WindowStartupLocation="CenterScreen"
ContentRendered ="On_ContentRendered"
Title="Choose A Picture" Height="515" Width="500" Background="Black" ResizeMode="CanMinimize">
<Grid Background="Black">
<ScrollViewer VerticalScrollBarVisibility="Disabled" HorizontalScrollBarVisibility="Auto" Height="420" VerticalAlignment="Top" Margin="0,5,0,0">
<StackPanel>
<StackPanel Name="HeadsPanel" Orientation="Horizontal" Height="100" VerticalAlignment="Top"/>
<StackPanel Name="AbstractPanel" Orientation="Horizontal" Height="100" VerticalAlignment="Top"/>
<StackPanel Name="ShapesPanel" Orientation="Horizontal" Height="100" VerticalAlignment="Top"/>
<StackPanel Name="MiscPanel" Orientation="Horizontal" Height="100" VerticalAlignment="Top"/>
</StackPanel>
</ScrollViewer>
<Button Name="CancelButton" VerticalAlignment="Bottom" Style="{DynamicResource RedButton}" Click="CancelButton_Click">Cancel</Button>
<Border Name="LoadingBorder" Background="Black">
<TextBlock Name="LoadingLabel" Foreground="White" VerticalAlignment="Center" HorizontalAlignment="Center" Margin="0,150" FontSize="20" FontWeight="Bold">
<Run>Loading Pictures</Run>
<LineBreak></LineBreak>
<Run>Please Wait...</Run>
</TextBlock>
</Border>
</Grid>
Here's the code behind the window:
namespace RandomApplication.Windows
{
public partial class ChooseProfilePic : Window
{
private readonly BackgroundWorker _loadPictureWorker = new BackgroundWorker();
public ChooseProfilePic()
{
InitializeComponent();
Topmost = true;
_loadPictureWorker.DoWork += LoadImages;
_loadPictureWorker.RunWorkerCompleted += LoadImages_Completed;
}
private void On_ContentRendered(object sender, EventArgs e)
{
_loadPictureWorker.RunWorkerAsync();
}
private void CancelButton_Click(object sender, RoutedEventArgs e)
{
DialogResult = false;
Close();
}
private void LoadImages(object sender, DoWorkEventArgs e)
{
try
{
var headsImagePath = AppDomain.CurrentDomain.BaseDirectory + #"Images\Profile Pics\Heads\";
var abstractImagePath = AppDomain.CurrentDomain.BaseDirectory + #"Images\Profile Pics\Abstract\";
var shapesImagePath = AppDomain.CurrentDomain.BaseDirectory + #"Images\Profile Pics\Shapes\";
var miscImagePath = AppDomain.CurrentDomain.BaseDirectory + #"Images\Profile Pics\Misc\";
List<string> headsImageList = GetImages(headsImagePath);
List<string> abstractImageList = GetImages(abstractImagePath);
List<string> shapesImageList = GetImages(shapesImagePath);
List<string> miscImageList = GetImages(miscImagePath);
Application.Current.Dispatcher.Invoke(() =>
{
LoadViewingPanel(headsImageList, HeadsPanel);
LoadViewingPanel(abstractImageList, AbstractPanel);
LoadViewingPanel(shapesImageList, ShapesPanel);
LoadViewingPanel(miscImageList, MiscPanel);
});
}
catch (Exception ex)
{
CustomMessageBox.Show("Could not load images. :-(", "Image Retrieval Failed", MessageBoxButton.OK,
MessageBoxImage.Error);
Helper.WriteException(Helper.ErrorLogs + "Error Loading Images.txt", ex);
}
}
private void LoadImages_Completed(object sender, RunWorkerCompletedEventArgs e)
{
if (e.Error != null)
{
CustomMessageBox.Show("Could not load images. :-(", "Image Retrieval Failed", MessageBoxButton.OK,
MessageBoxImage.Error);
Helper.WriteException(Helper.ErrorLogs + "Error Loading Images.txt", e.Error);
}
else LoadingBorder.Visibility = Visibility.Hidden;
}
public List<string> GetImages(string imagePath)
{
var that = GetAllFiles(imagePath);
return that.ToList();
}
private void LoadViewingPanel(List<string> list, StackPanel panel)
{
foreach (var imageString in list)
{
Helper.WriteLineToFile(Helper.ErrorLogs + "2nd Info Loading Images.txt", imageString);
var thisUri = new Uri(imageString, UriKind.RelativeOrAbsolute);
var pic = new ProfilePic {ProfilePicImage = {Source = new BitmapImage(thisUri)}};
panel.Children.Add(pic);
}
}
private IEnumerable<string> GetAllFiles(string path)
{
return Directory.EnumerateFiles(path, "*.jpg").Union(
Directory.EnumerateDirectories(path).SelectMany(d =>
{
try
{
return GetAllFiles(d);
}
catch
{
return Enumerable.Empty<string>();
}
}));
}
}
}
I've researched what could cause issues with this particular dll, but none of it seems to relate to my issue.
So, I figured out the issue. Apparently, the size of the images that I was trying to load was too big. The images were all 2048x2048 pixels, which made them anywhere from 180 KB to 380 KB in size. Apparently this is too much. I resized all of the pictures to 100x100 pixels (as I was only ever presenting them to the user as 100x100), which brought the file sizes down to 7 - 10 KB each. After that, they loaded just fine with no crashing issues.
Related
This is the xaml "SidiMessageBoxWindow.xaml" file:
<Window
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008" mc:Ignorable="d">
<Border>
<Grid x:Name="mainGrid" Margin="0">
<Grid.RowDefinitions>
<RowDefinition Height="*" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<ScrollViewer Grid.Row="0" VerticalScrollBarVisibility="Auto" Margin="0">
<TextBlock x:Name="TextBlock" TextWrapping="Wrap" Text="TextBlock" ScrollViewer.VerticalScrollBarVisibility="Auto" Height="Auto"/>
</ScrollViewer>
<Grid Grid.Row="1" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" Height="Auto" Width="Auto" Margin="0,10,0,0">
<Button x:Name="btnCancel" Content="Cancel" Width="Auto" MinWidth="0" Height="30"
HorizontalAlignment="Right" HorizontalContentAlignment="Center" VerticalAlignment="Center" VerticalContentAlignment="Center"
Margin="0,0,45,0" Padding="4,0,4,0" BorderThickness="1" />
<Button x:Name="btnOk" Content="Ok" Width="Auto" MinWidth="40" Height=" 30"
HorizontalAlignment="Right" HorizontalContentAlignment="Center" VerticalAlignment="Center" VerticalContentAlignment="Center"
Margin="0" Padding="4,0,4,0" BorderThickness="1" />
</Grid>
</Grid>
</Border>
and here the "SidiMessageBox1" class
I can't use "messageBox.ShowDialog();" here because I have to use the class "NTWindow" which I don't have access to.
public class SidiMessageBox1 : SidiMessageBoxWindow1
{
public static MessageBoxResult Show(ChartControl chartControl, string text, MessageBoxButton buttons = MessageBoxButton.OK)
{
if (chartControl == null)
{
return MessageBoxResult.None;
}
var messageBox = CreateMessageBox(chartControl, text, buttons);
messageBox.Show();
return messageBox.MsgBoxResult;
}
private static SidiMessageBoxWindow1 CreateMessageBox(ChartControl chartControl, string text, MessageBoxButton buttons)
{
return new SidiMessageBoxWindow1(text, buttons)
{
Owner = chartControl.OwnerChart,
Foreground = Application.Current.TryFindResource("FontControlBrush") as SolidColorBrush
};
}
}
and here is the SidiMessageBoxWindow1 class
public class SidiMessageBoxWindow1 : NTWindow
{
private static readonly string xamlFilePath = Path.Combine(Globals.UserDataDir, #"bin\Custom\AddOns\Sidi\SidiMessageBoxWindow.xaml");
private string text;
private Button btnOk, btnCancel;
private TextBlock textBlock;
private MessageBoxButton buttons;
public SidiMessageBoxWindow1()
{
}
public SidiMessageBoxWindow1(string text, MessageBoxButton buttons)
{
this.text = text;
Caption = "SidiMessageBox";
Topmost = true;
MinHeight = 100;
MinWidth = 200;
ResizeMode = ResizeMode.NoResize;
SizeToContent = SizeToContent.WidthAndHeight;
WindowStartupLocation = WindowStartupLocation.CenterOwner;
Content = LoadXaml(xamlFilePath);
Buttons = buttons;
}
private void OkButton_Click(object sender, RoutedEventArgs e)
{
btnOk.Click -= OkButton_Click;
Close();
}
private void CancelButton_Click(object sender, RoutedEventArgs e)
{
btnCancel.Click -= CancelButton_Click;
Close();
}
private DependencyObject LoadXaml(string xmlFilePath)
{
Window page;
FileStream fs = new FileStream(xmlFilePath, FileMode.Open);
page = (Window)XamlReader.Load(fs);
btnOk = LogicalTreeHelper.FindLogicalNode(page, "btnOk") as Button;
btnCancel = LogicalTreeHelper.FindLogicalNode(page, "btnCancel") as Button;
textBlock = LogicalTreeHelper.FindLogicalNode(page, "TextBlock") as TextBlock;
textBlock.Text = text;
return page.Content as DependencyObject;
}
public MessageBoxButton Buttons
{
get
{
return buttons;
}
set
{
buttons = value;
btnCancel.Visibility = Visibility.Collapsed;
btnOk.Visibility = Visibility.Collapsed;
switch (buttons)
{
case MessageBoxButton.OK:
btnOk.Visibility = Visibility.Visible;
btnOk.Click += OkButton_Click;
break;
case MessageBoxButton.OKCancel:
btnCancel.Visibility = Visibility.Visible;
btnOk.Visibility = Visibility.Visible;
btnOk.Click += OkButton_Click;
btnCancel.Click += CancelButton_Click;
break;
}
}
}
public MessageBoxResult MsgBoxResult { get; set; }
}
call:
var result = SidiMessageBox1.Show(ChartControl, "text");
the messageboxwindow looks like this:
everything works fine, as it should, except that I don't get a "MessageBoxResult" back. Unfortunately I don't know how to do that with this code.
I thank "BionicCode" for his explanation and hope for your understanding, because i am still quite a beginner ;-)
To use the Thread class is considered an obsolete programming model. Since the introduction of async and await with .NET Framework 4.5 the recommended programming model is the Microsoft Docs: Task asynchronous programming model.
As the member name Dispatcher.InvokeAsync suggests, this method is awaitable and supports asynchronous execution.
Your code actually does not execute the Window on a new thread. Because you use post related code to the Dispatcher, the Window is shown on the main thread.
Showing another Window will not block the other Window instances.
Additionally, your posted code is quite smelly. You should never block a constructor. But showing a modal dialog from a constructor will block construction. A constructor must initialize the members and return immediately.
Instead you must create and show the Window instance from your static Show method:
public static MessageBoxResult Show(ChartControl chartControl, string text, MessageBoxButton buttons)
{
if (chartControl == null)
{
return MessageBoxResult.None;
}
SidiMessageBoxWindow messageBox = CreateMessageBox(chartControl, text, buttons);
// If just an OK button, allow the user to just move away from the dialog
if (buttons == MessageBoxButton.OK)
{
messageBox.Show();
}
else
{
messageBox.ShowDialog();
}
return messageBox.MsgBoxResult;
}
private static SidiMessageBoxWindow CreateMessageBox(ChartControl chartControl, string text, MessageBoxButton buttons)
{
return new SidiMessageBoxWindow(xamlFilePath, logFilePath, text, buttons, chartControl)
{
Owner = chartControl.OwnerChart,
Foreground = Application.Current.TryFindResource("FontControlBrush") as SolidColorBrush
};
}
private SidiMessageBoxWindow(ChartControl chartControl, string text, MessageBoxButton buttons)
{
this.chartControl = chartControl;
this.text = text;
this.buttons = buttons;
}
i have a window that is acting like a Dialog with two buttons and a textbox, so its an input dialog, the problem is when i press the buttons, or close the dialog window in any way the main window that i used to create this dialog will get closed too! (exit code = 0) and another thing is that it will work OK in vs debugging but when i run the app without vs debugging that owner window get closed and in my case that window is the Main app window so the whole application will shutdown! what am i doing wrong?
XAML:
<Window x:Class="Server.Forms.Dialogs.PokeDialog"
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:Server.Forms.Dialogs"
mc:Ignorable="d"
Title="Poke" MinHeight="120" MinWidth="225"
ResizeMode="CanResizeWithGrip"
SizeToContent="WidthAndHeight"
x:Name="windowPoke"
Loaded="windowPoke_Loaded">
<StackPanel VerticalAlignment="Stretch"
HorizontalAlignment="Stretch"
Margin="25">
<Label Content="Poke Reason:"
Padding="0"/>
<TextBox x:Name="textboxPokeReason"
Margin="0 5"/>
<DockPanel>
<Button x:Name="btnOk"
Click="btnOk_Click"
IsDefault="True"
Content="OK"
MinWidth="100"
Margin="0 0 5 0"/>
<Button x:Name="btnCancel"
Click="btnCancel_Click"
IsCancel="True"
Content="Cancel"
MinWidth="100"/>
</DockPanel>
</StackPanel>
C#:
public partial class PokeDialog : Window
{
public string PokeReason
{
get { return textboxPokeReason.Text; }
}
public PokeDialog()
{
InitializeComponent();
}
private void windowPoke_Loaded(object sender, RoutedEventArgs e)
{
textboxPokeReason.Focus();
}
private void btnOk_Click(object sender, RoutedEventArgs e)
{
DialogResult = true;
}
private void btnCancel_Click(object sender, RoutedEventArgs e)
{
DialogResult = false;
}
}
the way i used dialog:
private void btnPokeClient_Click(object sender, RoutedEventArgs e)
{
var dialog = new PokeDialog();
if (dialog.ShowDialog() == true)
{
MessageBox.Show("TRUE - input text:" + dialog.PokeReason);
}
else MessageBox.Show("FALSE");
}
i can see the messageboxes too, but after closing this message boxes the whole app will get closed
I have successfully create a multilanguage application based from here. I was great when able to change language.
Now I have stuck in this situation. My application is operating with hardware. So there is one screen that having interaction with hardware and display status textblock. The message will be variant depend on the response from hardware e.g. "Please wait..", "Scan your ID into scanner", "Scan complete", "Profile identified, continue with transaction".
How do this variant can be display in multilingual into single textblock?
Assuming the textblock will be naming TbxStatus.Text. How do I set the message in ResourceDictionary file and how do I handle which resource string key that it should take?
EDITED [WHAT HAVE I TRIED]
This is the code that I've write to switch language and show based from resources dictionary:-
App.cs
public static String Directory;
public static App Instance;
public static event EventHandler LanguageChangedEvent;
public App()
{
// Initialize static variables
Instance = this;
Directory = System.IO.Path.GetDirectoryName(System.Reflection.Assembly.GetExecutingAssembly().Location);
Instance.SetLanguageResourceDictionary(Instance.GetLocXAMLFilePath("en-US"));
}
public static void LoadLanguageLocalization()
{
try
{
ViewModel.AppConfigViewModel.LocalizationProperty.LangLoc = new List<ApplicationModel.LanguageLocalization>
{
new ApplicationModel.LanguageLocalization { LanguageID = 1, CountryCode = "ms-MY", LanguageName = "Bahasa Malaysia" },
new ApplicationModel.LanguageLocalization { LanguageID = 2, CountryCode = "en-US", LanguageName = "English" },
new ApplicationModel.LanguageLocalization { LanguageID = 3, CountryCode = "zh-CN", LanguageName = "Chinese" },
new ApplicationModel.LanguageLocalization { LanguageID = 4, CountryCode = "ta-IN", LanguageName = "Tamil" }
};
}
catch (Exception ex)
{
LogEvents($"[App] Exception on LoadLanguageLocalization. Message-{ex.Message}. Stack Trace-{ex.StackTrace}", EventLogEntryType.Error);
ViewModel.AppConfigViewModel.LocalizationProperty.LangLoc = null;
}
}
public void SwitchLanguage(string inFiveCharLang)
{
if (System.Globalization.CultureInfo.CurrentCulture.Name.Equals(inFiveCharLang))
return;
var ci = new System.Globalization.CultureInfo(inFiveCharLang);
Thread.CurrentThread.CurrentCulture = ci;
Thread.CurrentThread.CurrentUICulture = ci;
SetLanguageResourceDictionary(GetLocXAMLFilePath(inFiveCharLang));
LanguageChangedEvent?.Invoke(this, new EventArgs());
}
private string GetLocXAMLFilePath(string inFiveCharLang)
{
string locXamlFile = "Resources." + inFiveCharLang + ".xaml";
return Path.Combine(Directory, "Language", locXamlFile);
}
public void SetLanguageResourceDictionary(String inFile)
{
if (File.Exists(inFile))
{
// Read in ResourceDictionary File
var languageDictionary = new ResourceDictionary();
languageDictionary.Source = new Uri(inFile);
// Remove any previous Localization dictionaries loaded
int langDictId = -1;
for (int i = 0; i < Resources.MergedDictionaries.Count; i++)
{
var md = Resources.MergedDictionaries[i];
// Make sure your Localization ResourceDictionarys have the ResourceDictionaryName
// key and that it is set to a value starting with "Loc-".
if (md.Contains("LanguageDictionaryName"))
{
if (md["LanguageDictionaryName"].ToString().StartsWith("Lang-"))
{
langDictId = i;
break;
}
}
}
if (langDictId == -1)
{
// Add in newly loaded Resource Dictionary
Resources.MergedDictionaries.Add(languageDictionary);
}
else
{
// Replace the current langage dictionary with the new one
Resources.MergedDictionaries[langDictId] = languageDictionary;
}
}
}
SelectLanguage.cs
private async void Page_Loaded(object sender, RoutedEventArgs e)
{
try
{
App.LogEvents($"[{PageTitle}] Loaded: Select language", System.Diagnostics.EventLogEntryType.Information);
BindingToPropertyControl();
}
catch (System.Exception ex)
{
string error = $"[{PageTitle}] Exception on Page_Loaded. Message: {ex.Message}. StackTrace: {ex.StackTrace}";
App.LogEvents(error, System.Diagnostics.EventLogEntryType.Error);
}
}
private void BindingToPropertyControl()
{
try
{
if (ViewModel.AppConfigViewModel.LocalizationProperty.LangLoc != null)
{
LanguagePack.ItemsSource = ViewModel.AppConfigViewModel.LocalizationProperty.LangLoc;
}
}
catch (System.Exception ex)
{
string error = $"[{PageTitle}] Exception on BindingToPropertyControl. Message: {ex.Message}. StackTrace: {ex.StackTrace}";
App.LogEvents(error, System.Diagnostics.EventLogEntryType.Error);
}
}
private void Button_Click(object sender, RoutedEventArgs e)
{
try
{
ScreenTimer.Stop();
Button btn = (Button)sender;
string LangCode = btn.Tag.ToString();
App.LogEvents($"[{PageTitle}] Selecting language: {LangCode}", System.Diagnostics.EventLogEntryType.Information);
App.Instance.SwitchLanguage(LangCode.ToString());
Dispatcher.BeginInvoke(DispatcherPriority.Send, new Action(delegate ()
{
NavigationService.Navigate(new Uri(ApplicationModel.NaviModel.NaviSelectOptions, UriKind.RelativeOrAbsolute));
}));
}
catch (System.Exception ex)
{
string error = $"[{PageTitle}] Exception on Button_Click. Message: {ex.Message}. StackTrace: {ex.StackTrace}";
App.LogEvents(error, System.Diagnostics.EventLogEntryType.Error);
}
}
SelectLanguage.xaml
<ScrollViewer x:Name="ScrollLanguage" HorizontalScrollBarVisibility="Hidden" VerticalScrollBarVisibility="Hidden">
<WrapPanel Height="Auto" Width="{Binding ElementName=ScrollLanguage, Path=ViewportWidth}">
<ItemsControl Name="LanguagePack">
<ItemsControl.ItemTemplate>
<DataTemplate>
<Grid Margin="0,20" VerticalAlignment="Stretch" Width="{Binding ElementName=ScrollLanguage, Path=ViewportWidth}">
<Button Click="Button_Click" Tag="{Binding CountryCode}" Content="{Binding LanguageName}" VerticalAlignment="Center" Height="150" FontSize="60" Background="#FF1A5C9E" BorderBrush="{x:Null}"/>
</Grid>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
</WrapPanel>
</ScrollViewer>
SelectOptions.xaml
<TextBlock x:Name="tbTitle" TextWrapping="Wrap" Text="{StaticResource ResourceKey=SelectMerchant_Title}" FontSize="100" TextAlignment="Center" Padding="0,0,0,50" Foreground="White"/>
<Button x:Name="btnEatIn" Content="{StaticResource ResourceKey=SelectMerchant_Opt1}" VerticalAlignment="Center" Height="150" FontSize="60" Background="#FF057A5A" BorderBrush="{x:Null}"/>
<Button x:Name="btnEatIn" Content="{StaticResource ResourceKey=SelectMerchant_Opt2}" VerticalAlignment="Center" Height="150" FontSize="60" Background="#FF057A5A" BorderBrush="{x:Null}"/>
Resources.en-US.xaml
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:sys="clr-namespace:System;assembly=mscorlib">
<!-- The name of this ResourceDictionary. Should not be localized. -->
<sys:String x:Key="LanguageDictionaryName" Localization.Comments="$Content(DoNotLocalize)">Lang-en-US</sys:String>
<!-- Localization specific styles -->
<FlowDirection x:Key="FlowDirection_Default" Localization.Comments="$Content(DoNotLocalize)">LeftToRight</FlowDirection>
<!--<FlowDirection x:Key="FlowDirection_Reverse" Localization.Comments="$Content(DoNotLocalize)">RightToLeft</FlowDirection>-->
<!-- SELECT ORDER TYPE -->
<sys:String x:Key="SelectMerchant_Title">Self-Service Kiosk</sys:String>
<sys:String x:Key="SelectMerchant_Opt1">Register new applicant</sys:String>
<sys:String x:Key="SelectMerchant_Opt2">Meal Application</sys:String>
</ResourceDictionary>
Back to what I'm facing, I can show different language by using resource key, but how to I display message or status which is dynamically (not static) into the display in multi-language?
Example, on validation screen, I have one TextBlock and currently I'm subscribe the event raise from hardware. How to show the status based from language that has been selected?
.
<StackPanel VerticalAlignment="Top" Margin="120,180,120,0" Grid.Row="1">
<TextBlock x:Name="tbGeneralStatus" TextWrapping="Wrap" Text="Please wait..." TextAlignment="Center" FontSize="50" Foreground="Yellow"/>
</StackPanel>
tbGeneralStatus.Text will show "Please wait..", "Scan your ID into scanner", "Scan complete", "Profile identified, continue with transaction" from delegate event from Barcode Scanner class.
I think you need to look a little into MVVM to make things easier with WPF. It takes some effort at the beggining, but its absolutely worth. I thought you were stucked only on how to receive and translate the status, so I'll try to give more info after looking at the code.
A quick guidance, based on Enum localization but not verified in dept.
You need a viewmodel to act as datacontext of the window you want to update. It has to implement INotifyPropertyChange interface to update the status in live.
class YourWindowViewModel : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
private string _statusText = string.Empty;
public string StatusText
{
get { return _statusText; }
set
{
_statusText = value;
OnPropertyChanged("StatusText");
}
}
public void YourMessageHandler(Status newStatus)
{
StatusText = GetLocalizedStatusText(newStatus);
}
private string GetLocalizedStatusText(Status newStatus)
{
switch (newStatus)
{
case Status.Wait: return Resources.StatusWaiting;
case Status.Continue: return Resources.StatusContinue;
case Status.Scan: return Resources.StatusScanId;
default: return string.Empty;
}
}
}
public enum Status
{
Wait,
Scan,
Continue
}
To bind to your window, make it like this:
<Window.DataContext>
<local:YourWindowViewModel/>
</Window.DataContext>
and change your TextBlock control to bind to the StatusText on the viewmodel
<StackPanel VerticalAlignment="Top" Margin="120,180,120,0" Grid.Row="1">
<TextBlock TextWrapping="Wrap" Text="{Binding StatusText}" TextAlignment="Center" FontSize="50" Foreground="Yellow"/>
</StackPanel>
Note that as I don't know your delegate/msgHandler format, I have put a generic "YourMessageHandler" method which receive the changing status
I'm trying to achieve one Login button which changes to a Please wait... mode once pressed. I was thinking about some StoryBoard animation inside button or GIF image animation. Seems I'm pretty new to WPF and after several search attempts, I'm unable to find a fully working idea.
Login button idea
What would be the best way to do the above thing? Is there any way to eliminate the GIF image and create the same using some Path or something similar? Also note that I want this behavior of button to be triggered on Button.Click event.
Just simply add WpfAnimatedGif from your visual studio Tools -> NuGet Package Manager->Package Manager Console. There you find the Package adder window and type pm > Install-Package WpfAnimatedGif. After a few seconds package should be added. Now firstly, you have add namespace xmlns:gif="http://wpfanimatedgif.codeplex.com" then design your Button.
<Window x:Class="WpfApplication1.MainWindow" Name="root"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:gif="http://wpfanimatedgif.codeplex.com"
Width="500" Height="500" DataContext="{Binding ElementName=root}">
<StackPanel>
<Button Name="BtnLogin" Width="100" Height="30" Content="Login" Background="Red" Margin="0,0,0,5" Click="Button_Click"/>
<Button Width="100" Height="30" Background="Red">
<Grid>
<Image gif:ImageBehavior.AnimatedSource="{Binding DataContext.LoadingImage}" HorizontalAlignment="Left" VerticalAlignment="Center"/>
<TextBlock Text="Please Wait" Padding="30,0,0,0" HorizontalAlignment="Right" VerticalAlignment="Center"/>
</Grid>
</Button>
</StackPanel>
</Window>
The following .cs file is below and when you need to stop loading image, just assign LoadingImage = null;
public partial class MainWindow : Window,INotifyPropertyChanged
{
public MainWindow()
{
InitializeComponent();
}
private ImageSource _LoadingImage;
public ImageSource LoadingImage
{
get { return _LoadingImage; }
set
{
_LoadingImage = value;
OnPropertyChanged("LoadingImage");
}
}
public event PropertyChangedEventHandler PropertyChanged;
private void OnPropertyChanged(String info)
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(info));
}
}
private void Button_Click(object sender, RoutedEventArgs e)
{
LoadingImage = GetBitmapImage("/aaaa.gif");
}
public static BitmapImage GetBitmapImage(String location)
{
BitmapImage image = null;
try
{
Uri iconUri = new Uri("pack://application:,,,/" + ";component" + location, UriKind.RelativeOrAbsolute);
image = new BitmapImage(iconUri);
}
catch (Exception ex)
{
}
return image;
}
}
I have a project that uses a System.Windows.Controls.Primatives.Popup to drag a 'tooltip' like control along with a mouse.
Whenever the drag crosses a horizontal line the popup 'wraps' to the bottom of the screen - despite having sane values for the VerticalOffset. The point at which this wrapping occurs appears to be tied to the HEIGHT of the window, but not it's position.
Here's the code from the sandbox project I have created that also exhibits the same behavior:
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
this.MainGrid.MouseDown += Grid_MouseDown;
this.MainGrid.MouseUp += Grid_MouseUp;
this.MainGrid.MouseMove += (s, e) => { if (this.Popup.IsOpen) { Popup_Drag(s, e); } };
this.Popup.MouseMove += Popup_Drag;
}
private void Popup_Drag(object sender, MouseEventArgs e)
{
Popup.HorizontalOffset = e.GetPosition(this.Popup).X;
Popup.VerticalOffset = e.GetPosition(this.Popup).Y;
this.Status_Top.Text = String.Format("Height/Top: {0}/{1} Width/Left: {2}/{3}", this.Height, this.Top, this.Width, this.Left);
this.Status.Text = String.Format("Vertical Offset: {0} Horizontal Offset: {1}", Popup.VerticalOffset, Popup.HorizontalOffset);
}
private void Grid_MouseUp(object sender, MouseButtonEventArgs e)
{
this.Popup.IsOpen = false;
}
private void Grid_MouseDown(object sender, MouseButtonEventArgs e)
{
this.Popup.IsOpen = true;
Popup_Drag(sender, e);
}
}
And the Window XAML:
<Window x:Class="WpfSandbox.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow" Height="350" Width="525">
<Grid x:Name="MainGrid" Background="Purple">
<TextBlock x:Name="Status_Top"></TextBlock>
<Popup x:Name="Popup" Cursor="Hand" HorizontalAlignment="Left"
VerticalAlignment="Bottom" IsOpen="True">
<TextBlock Background="Blue" Foreground="White">
<TextBlock x:Name="Status">TEXT</TextBlock></TextBlock>
</Popup>
</Grid>
</Window>
I was able to fix this by adding Placement="RelativePoint" to the Popup attributes. Apparently this is the default in Silverlight, but not WPF.