How do I properly implement a UWP C# subclass of Grid? - c#

I am working on implementing a feature into a UWP app where when a Grid item is hovered over in a AdaptiveGridView that after 2 seconds it will show a popup with more details about the hovered item in the form of another formatted Grid. This was working just fine until I needed to add a 2-second delay before the popup appears.
I have been adapting a similar thread in an attempt to make this work (How to use mousehover delay in c#?) but I have not been able to override the PointerEntered/PointerExited functions due to some errors:
Line 43: CS0505: 'HoverGrid.PointerEntered(PointerEventHandler)': cannot override because 'UIElement.PointerEntered' is not a function
Line 45: CS0079: The event 'UIElement.PointerEntered' can only appear on the left hand side of += or -=
To be honest, I am not sure if this is the best way to implement the hover delayed event either, but its something I am trying
Currently I have created a HoverGrid.cs class that is receiving the errors (below). I have tried tweaking the arguments/naming of the methods but it doesnt seem to do anything.
I have also tried to implement Timers directly in the page that has the events I am ultimately working with, but I was having issues with that which is why I am trying this method out if possible.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Windows.UI.Xaml.Controls;
using Windows.UI.Xaml.Input;
namespace ViperContentManager.Classes.Controls
{
public class HoverGrid : Windows.UI.Xaml.Controls.Grid
{
protected System.Timers.Timer timer;
public bool IsHoverEnabled { get; set; }
public double Delay { get; set; }
public event System.Timers.ElapsedEventHandler TimerElapsed
{
add
{
timer.Elapsed += value;
}
remove
{
timer.Elapsed -= value;
}
}
public HoverGrid()
{
// defaults: hover trigger enabled with 3000 ms delay
IsHoverEnabled = true;
Delay = 3000;
timer = new System.Timers.Timer
{
AutoReset = false,
Interval = Delay
};
}
protected override void PointerEntered(PointerEventHandler e)
{
base.PointerEntered();
if (IsHoverEnabled)
{
timer.Start();
}
}
protected override void PointerExited(PointerEventHandler e)
{
base.PointerExited();
timer.Stop();
}
}
}
For anyone curious, this is what the code-behind for the page that would be hosting the hoverGrid looks like (although HoverGrid is not yet implemented into my XAML at all). Forgive some of the extra variable declarations, I was trying to implement the hover function a few ways and haven't yet cleaned it up.
using Microsoft.Toolkit.Uwp.UI;
using Microsoft.Toolkit.Uwp.UI.Controls;
using System.Diagnostics;
using Windows.Foundation;
using Windows.UI.Xaml;
using Windows.UI.Xaml.Controls;
using Windows.UI.Xaml.Controls.Primitives;
using Windows.UI.Xaml.Data;
using Windows.UI.Xaml.Input;
using Windows.UI.Xaml.Media;
using Windows.UI.Xaml.Navigation;
using Windows.UI.Core;
namespace MyProject.Pages
{
public sealed partial class ImageUploaderPage : Page
{
public object selected = null;
public double thumbSize = 150;
//Variables for on-hover popup
public double detailPopLeft, detailPopRight, detailPopTop, detailPopBottom;
public Rect winBounds = new Rect(0,0,0,0);
public UIElement winContent = null;
public Windows.UI.Xaml.Window currentWindow = null;
public GeneralTransform hovTransform = null;
public Point hovPointToWindow = new Point(0,0);
public System.Timers.Timer hoverTimer = new System.Timers.Timer();
public object hoveredImage = null;
public PointerRoutedEventArgs hoveredImageArgs = null;
public ImageUploaderPage()
{
this.InitializeComponent();
//Create and set up the HoverTimer
hoverTimer = new System.Timers.Timer();
hoverTimer.Interval = 2000;
hoverTimer.Elapsed += OnTimerElapsed;
hoverTimer.AutoReset = true;
}
//public event System.Timers.ElapsedEventHandler TimerElapsed
//{ add { hoverTimer.Elapsed += value; } remove { hoverTimer.Elapsed -= value; } }
private void onImageHover(object sender, PointerRoutedEventArgs e)
{
hoveredImage = sender;
Grid img = (Grid)sender;
hoveredImageArgs = e;
hoverTimer.Stop();
hoverTimer.Start();
currentWindow = Window.Current;
winBounds = Window.Current.Bounds;
winContent = Window.Current.Content;
GeneralTransform transform = img.TransformToVisual(winContent);
hovPointToWindow = transform.TransformPoint(new Point(0, 0));
}
private void onImageEndHover(object sender, PointerRoutedEventArgs e)
{
hoverTimer.Stop();
hoveredImage = null;
hoveredImageArgs = null;
}
private void OnTimerElapsed(object source, System.Timers.ElapsedEventArgs e)
{
Debug.WriteLine("Timer elapsed!");
hoverTimer.Stop();
if (hoveredImage.GetType().ToString() == "Windows.UI.Xaml.Controls.Grid")
{
//Get the hovered image and associated arguments that were stored
Grid img = (Grid)hoveredImage;
PointerRoutedEventArgs f = hoveredImageArgs;
//Get image position and bounds
GeneralTransform transform = img.TransformToVisual(Window.Current.Content);
Point coordinatePointToWindow = transform.TransformPoint(new Point(0, 0));
Rect winBounds = Window.Current.Bounds;
img.Visibility = Visibility.Visible;
double imgX1 = coordinatePointToWindow.X;
double imgX2 = imgX1 + img.ActualWidth;
double imgY1 = coordinatePointToWindow.Y;
double imgY2 = imgY1 + img.ActualHeight;
// (other logic here to determine pop position and display things in the UI)
}
}
}

Your issue here is that you're trying to use a function to override a property.
Because UIElement.PointerEntered is an Event, you need to assign a delegate(of type PointerEventHandler) to it instead.
Here's an example snippet:
// Your constructor
public HoverGrid()
{
this.PointerEntered += HandlePointerEntered;
// Do other setup
}
protected void HandlePointerEntered(object sender, PointerRoutedEventArgs args)
{
// Handle somehow
}

Related

GTK# Widget Gtk:: DrawingArea not displaying or responding to signals

I am using MonoDevelop IDE on linux/UNIX machine and coding in C# and .NET framework. I cannot seem to figure out how to get the Gtk::DrawingArea to show up in the parent Gtk.Window when the project builds?
I have tried adding a ::drawingArea object manually into the Code, placing it directly on the window (in the design view, see screenshot) and then I also tried placing the ::drawingArea object within a Fixed box.
Below is the code that I am trying to implement. The Design is as basic as you can get, just so I can understand catching and working with the signals to the drawingArea - it has the parent window (MainWindow) and the drawing area (drawingarea1).
Screenshot
My question: How can I get a drawingArea object to display in a Gtk.Window? And, more importantly is there something I am missing to make the object respond to signals that are set to the drawingarea? I want to ultimately be able to draw and color inside the drawing area window but as of right now I can't even get the drawing area widget to display and catch signals.
Thanks in advance!
MainWidow.cs
using System;
using Gtk;
public partial class MainWindow : Gtk.Window
{
public DrawingArea d;
public MainWindow() : base(Gtk.WindowType.Toplevel)
{
d = drawingarea1;
Build();
}
protected void OnDeleteEvent(object sender, DeleteEventArgs a)
{
Application.Quit();
a.RetVal = true;
}
protected void OnExpose(object o, ExposeEventArgs args)
{
Console.WriteLine("OnExpose...");
}
protected void OnRealization(object sender, EventArgs e)
{
Console.WriteLine("OnRealization...");
}
protected void OnDragMotion(object o, DragMotionArgs args)
{
Console.WriteLine("OnDragMotion...");
}
}
Driver.cs
using System;
using Gtk;
class MainClass
{
public static void Main(string[] args)
{
Application.Init();
MainWindow win = new MainWindow();
// throws NULLREFERENCE EXECPTION
win.d.Show();
win.Show();
Application.Run();
}
}
//******* PARTIAL SOLUTION **********//
ColorSelectorDraw.cs
using System;
using Gtk;
using Gdk;
namespace GUIDraw4
{
public class DemoColorSelection : Gtk.Window
{
private Gdk.Color color;
private Gtk.DrawingArea drawingArea;
public DemoColorSelection() : base("Color Selection")
{
BorderWidth = 8;
VBox vbox = new VBox(false, 8);
vbox.BorderWidth = 8;
Add(vbox);
// Create the color swatch area
Frame frame = new Frame();
frame.ShadowType = ShadowType.In;
vbox.PackStart(frame, true, true, 0);
drawingArea = new DrawingArea();
drawingArea.ExposeEvent += new ExposeEventHandler(ExposeEventCallback);
// set a minimum size
drawingArea.SetSizeRequest(400, 250);
// set the color
color = new Gdk.Color(255, 255, 255);
drawingArea.ModifyBg(StateType.Normal, color);
frame.Add(drawingArea);
Alignment alignment = new Alignment(1.0f, 0.5f, 0.0f, 0.0f);
Button button = new Button("_Change the above color");
button.Clicked += new EventHandler(ChangeColorCallback);
alignment.Add(button);
vbox.PackStart(alignment);
ShowAll();
}
protected override bool OnDeleteEvent(Gdk.Event evt)
{
Destroy();
return true;
}
// Expose callback for the drawing area
private void ExposeEventCallback(object o, ExposeEventArgs args)
{
EventExpose eventExpose = args.Event;
Gdk.Window window = eventExpose.Window;
Rectangle area = eventExpose.Area;
window.DrawRectangle(drawingArea.Style.BackgroundGC(StateType.Normal),
true,
area.X, area.Y,
area.Width, area.Height);
args.RetVal = true;
}
private void ChangeColorCallback(object o, EventArgs args)
{
using (ColorSelectionDialog colorSelectionDialog = new ColorSelectionDialog("Changing color"))
{
colorSelectionDialog.TransientFor = this;
colorSelectionDialog.ColorSelection.PreviousColor = color;
colorSelectionDialog.ColorSelection.CurrentColor = color;
colorSelectionDialog.ColorSelection.HasPalette = true;
if (colorSelectionDialog.Run() == (int)ResponseType.Ok)
{
Gdk.Color selected = colorSelectionDialog.ColorSelection.CurrentColor;
drawingArea.ModifyBg(StateType.Normal, selected);
}
colorSelectionDialog.Hide();
}
}
}
}
Program.cs
using System;
using Gtk;
namespace GUIDraw4
{
class MainClass
{
public static void Main(string[] args)
{
Application.Init();
//MainWindow win = new MainWindow();
//win.Show();
DemoColorSelection cs = new DemoColorSelection();
Application.Run();
}
}
}
This seemed to at least get an interactive drawing board up on the GUI. Taken from csharp.hotexamples.com

How to show a spelling error suggestions popup on mouse over a WPF TextBox with spell checking enabled in Winforms C#?

I am using element host to use WPF spell checker textbox in my winforms.
I want to override the context menu that appears on misspelled red squiggles to mouse hover instead of right click.
How to do that?
Tried overriding the behavior but it is still the same:
using System;
using System.ComponentModel;
using System.ComponentModel.Design.Serialization;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Forms.Integration;
using System.Windows.Forms.Design;
[Designer(typeof(ControlDesigner))]
class SpellCheck: ElementHost
{
privated TextBox box;
public SpellCheck()
{
box = new TextBox();
base.Child = box;
box.TextChanged += (s, e) => OnTextChanged(EventArgs.Empty);
box.SpellCheck.IsEnabled = true;
box.VerticalScrollBarVisibility = ScrollBarVisibility.Auto;
}
[DefaultValue(false)]
public bool Multiline
{
//checks for multiline
}
public bool IsEnabled
{
//checks for spell check enabled or not
}
[DefaultValue(false)]
public bool WordWrap
{
//does wordwraps
}
[DefaultValue(false)]
public int MaxLength
{
//maxlength property
}
[DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
public new System.Windows.UIElement Child
{
get { return base.Child; }
set { }
}
}
It shows spell suggestions on right click. I want to change it to Mouse hover or any other mouse events.
You could use TextBox.PreviewMouseMove to show a popup to achieve this.
You also need to create a new Form to serve as a popup. This Form could contain a FlowLayoutPanel to host the suggestions. In this example the Form is named CustomPopup:
box.PreviewMouseMove += OpenContextMenuOnMouseMove;
The event handler for TextBox.PreviewMouseMove:
private void OpenContextMenuOnMouseMove(object sender, System.Windows.Input.MouseEventArgs mouseEventArgs)
{
var textBox = sender as System.Windows.Controls.TextBox;
var mouseOverTextIndex = textBox.GetCharacterIndexFromPoint(mouseEventArgs.GetPosition(textBox), false);
// Pointer is not over text
if (mouseOverTextIndex.Equals(-1))
{
return;
}
int spellingErrorIndex = textBox.GetNextSpellingErrorCharacterIndex(mouseOverTextIndex, LogicalDirection.Forward);
// No spelling errors
if (spellingErrorIndex.Equals(-1))
{
return;
}
int startOfWordIndex = mouseOverTextIndex;
while (startOfWordIndex != -1 && !textBox.Text[startOfWordIndex].Equals(' '))
{
startOfWordIndex--;
}
var endOfWordIndex = textBox.Text.IndexOf(" ", mouseOverTextIndex, StringComparison.OrdinalIgnoreCase);
if (endOfWordIndex.Equals(-1))
{
endOfWordIndex = textBox.Text.Length - 1;
}
// Spelling error doesn't belong to current mouse over word
if (spellingErrorIndex < startOfWordIndex || spellingErrorIndex > endOfWordIndex)
{
return;
}
using(CustomPopup popup = new CustomPopup())
{
// Create clickable suggestions for the CustomPopup.
foreach (var suggestion in textBox.GetSpellingError(spellingErrorIndex).Suggestions)
{
// Each Button represents a suggestion.
var suggestionButton = new System.Windows.Forms.Button() { Text = suggestion };
var fixSpellingErrorEventArgs = new FixSpellingErrorEventArgs()
{
TargetTextBox = textBox,
WordStartIndex = startOfWordIndex,
WordEndIndex = endOfWordIndex,
Suggestion = suggestion
};
// The Button.Click callback will apply the selected fix
suggestionButton.Click += (s, e) => FixSpellingError_OnButtonClicked(fixSpellingErrorEventArgs);
// TODO::Replace the line with a public member of CustomPopup Form: CustomPopup.AddPanelContent(Control):void.
// e.g. public void AddPanelContent(Control control) { this.FlowLayoutPanel1.Controls.Add(suggestionButton); }
// and use it like: popup.AddPanelContent(suggestionButton);
popup.FlowLayoutPanel1.Controls.Add(suggestionButton);
}
popup.SetDesktopLocation((int) mouseEventArgs.GetPosition(textBox).X, (int) mouseEventArgs.GetPosition(textBox).Y);
popup.ShowDialog(this);
}
}
// The event handler that applies the selected fix.
// Invoked on popup button clicked.
private void FixSpellingError_OnButtonClicked(FixSpellingErrorEventArgs e)
{
// Select misspelled word and replace it with the selected fix
e.TargetTextBox.SelectionStart = e.WordStartIndex;
e.TargetTextBox.SelectionLength = e.WordEndIndex - e.WordStartIndex;
e.TargetTextBox.SelectedText = e.Suggestion;
}
The custom event arg object for Button.Click event
class FixSpellingErrorEventArgs : EventArgs
{
public System.Windows.Controls.TextBox TargetTextBox { get; set; }
public int WordStartIndex { get; set; }
public int WordEndIndex { get; set; }
public string Suggestion { get; set; }
}
To enhance the example create the logic how or when the popup will disappear (time out and focus lost?).

Show Image for ToolStripControlHost in drop down menu

I have a ToolStripSplitButton with various elements in dropdown list.
One of them is a Trackbar enclosed in a ToolStripControlHost, called ToolStripTrackbarItem. It's code (I've got it from stackoverflow):
using System;
using System.ComponentModel;
using System.Drawing;
using System.Windows.Forms;
using System.Windows.Forms.Design;
namespace Application
{
[System.ComponentModel.DesignerCategory("code")]
[System.Windows.Forms.Design.ToolStripItemDesignerAvailability(ToolStripItemDesignerAvailability.ContextMenuStrip | ToolStripItemDesignerAvailability.MenuStrip)]
public class ToolStripTrackbarItem : ToolStripControlHost
{
public ToolStripTrackbarItem()
: base(CreateControlInstance())
{
this.Size = Control.Size;
}
public TrackBar TrackBar
{
get { return Control as TrackBar; }
}
private static Control CreateControlInstance()
{
TrackBar t = new TrackBar();
t.AutoSize = false;
return t;
}
[DefaultValue(0)]
public int Value
{
get { return TrackBar.Value; }
set { TrackBar.Value = value; }
}
protected override void OnSubscribeControlEvents(Control control)
{
base.OnSubscribeControlEvents(control);
TrackBar trackBar = control as TrackBar;
trackBar.ValueChanged += new EventHandler(trackBar_ValueChanged);
}
protected override void OnUnsubscribeControlEvents(Control control)
{
base.OnUnsubscribeControlEvents(control);
TrackBar trackBar = control as TrackBar;
trackBar.ValueChanged -= new EventHandler(trackBar_ValueChanged);
}
void trackBar_ValueChanged(object sender, EventArgs e)
{
if (this.ValueChanged != null)
ValueChanged(sender, e);
}
public event EventHandler ValueChanged;
protected override Size DefaultSize
{
get { return new Size(300, 16); }
}
}
It works, but I need to show images to the left of the dropdown items:
I'm successful with a simple ToolStripMenuItem by setting the Image property. However, it is ineffective to set Image property of my ToolStripTrackbarItem (that is inherited from ToolStripControlHost, see code above). According to MSDN, Image property is irrelevant to ToolStripControlHost.
What does it mean? Is it not even possible to include an image left to ToolStripControlHost?
If it is possible anyway, how to do that?
You should solve 2 problems here:
ToolStripControlHost doesn't show Image property and also doesn't serialize the image when you save the form.
ToolStripProfessionalRendered doesn't draw image for ToolStripControlHost.
You need to override Image property of ToolStripControlHost and make it browsable and serializable. Also you need to create a custom renderer to draw the image in the correct location and size. Then if you simply set the renderer for ToolStrip using below code, you will get expected result:
this.toolStrip1.Renderer = new MyCustomRenderer();
ToolStripTrackBar
The item enables Image property to show in property grid and let it serialize when saving form.
using System.ComponentModel;
using System.Drawing;
using System.Linq;
using System.Windows.Forms;
using System.Windows.Forms.Design;
[ToolStripItemDesignerAvailability(ToolStripItemDesignerAvailability.All)]
public class ToolStripTrackBar : ToolStripControlHost
{
public TrackBar TrackBar { get { return (TrackBar)Control; } }
public ToolStripTrackBar() : base(CreateControl()) { }
private static TrackBar CreateControl()
{
var t = new TrackBar()
{ TickStyle = TickStyle.None, AutoSize = false, Height = 28 };
return t;
}
[Browsable(true)]
[DesignerSerializationVisibility(DesignerSerializationVisibility.Visible)]
public override Image Image
{
get { return base.Image; }
set { base.Image = value; }
}
/*Expose properties and events which you need.*/
public int Value
{
get { return TrackBar.Value; }
set { TrackBar.Value = value; }
}
}
MyCustomRenderer
This renderer draws images for ToolStripTrackBar.
using System.Drawing;
using System.Linq;
using System.Windows.Forms;
public class MyCustomRenderer : ToolStripProfessionalRenderer
{
protected override void OnRenderImageMargin(ToolStripRenderEventArgs e)
{
base.OnRenderImageMargin(e);
e.ToolStrip.Items.OfType<ToolStripTrackBar>()
.ToList().ForEach(item =>
{
if (item.Image != null)
{
var size = item.GetCurrentParent().ImageScalingSize;
var location = item.Bounds.Location;
location = new Point(5, location.Y + 1);
var imageRectangle = new Rectangle(location, size);
e.Graphics.DrawImage(item.Image, imageRectangle,
new Rectangle(Point.Empty, item.Image.Size),
GraphicsUnit.Pixel);
}
});
}
}

Modal dialog like system MessageBox in Windows Phone

I would like to make my own class for setting some values in dialog box in the way that MessageBox.Show() does.
My code is:
MainPage.xaml.cs
using System;
using System.Windows;
using Microsoft.Phone.Controls;
namespace ModalWindow
{
public partial class MainPage : PhoneApplicationPage
{
public MainPage()
{
InitializeComponent();
string result = MyModalBox.GiveMeValue();
MessageBox.Show(result);
}
}
}
MyModalBox.cs
using System;
using System.Windows;
using System.Windows.Media;
using System.Windows.Controls;
using System.Windows.Controls.Primitives;
namespace ModalWindow
{
public class MyModalBox
{
private static Popup modalBox;
public static string GiveMeValue()
{
TextBox textBox = new TextBox();
textBox.Width = 300;
textBox.Height = 100;
Button okButton = new Button();
okButton.Click += okButton_Click;
okButton.Content = "ok";
okButton.Width = 300;
okButton.Height = 100;
StackPanel stack = new StackPanel();
stack.Background = new SolidColorBrush(Colors.Black);
stack.Width = Application.Current.Host.Content.ActualWidth;
stack.Height = Application.Current.Host.Content.ActualHeight;
stack.HorizontalAlignment = HorizontalAlignment.Center;
stack.VerticalAlignment = VerticalAlignment.Center;
stack.Children.Add(textBox);
stack.Children.Add(okButton);
modalBox = new Popup();
modalBox.Child = stack;
modalBox.IsOpen = true;
// how to change my code to return value only after okButton is cklicked?
return textBox.Text;
}
static void okButton_Click(object sender, RoutedEventArgs e)
{
modalBox.IsOpen = false;
}
}
}
Of course it shows no result befor popup appears. How can I change my code to return value onli after clicking button? Is it possible?
Thanks in advance!
You can use TaskComplectionSource for that.
Add this:
public class DialogResult<T>
{
private readonly T _result;
private readonly bool _canceled;
public DialogResult(bool isCanceled)
: this(string.Empty, isCanceled)
{
}
public DialogResult(string result, bool canceled = false)
{
_result = result;
_canceled = canceled;
}
public T GetResults()
{
if (HasDialogBeenCanceled())
throw new InvalidOperationException("Dialog has been canceled - no results");
return _result;
}
public bool HasDialogBeenCanceled()
{
return _canceled;
}
}
// inside your dialog control
private TaskCompletionSource<DialogResult<string>> dialogResultAwaiter;
private Button button;
private TextBlock textBox;
private Popup popup;
public async Task<DialogResult<string>> ShowPopup()
{
dialogResultAwaiter = new TaskCompletionSource<DialogResult<string>>();
button.Tapped += (sender, args) => dialogResultAwaiter.SetResult(new DialogResult<string>(textBox.Text, false));
var popup = new Popup();
popup.Closed += PopupOnClosed;
// popup code
popup.IsOpen = true;
return await dialogResultAwaiter.Task;
}
private void PopupOnClosed(object sender, object o)
{
if (dialogResultAwaiter.Task.IsCompleted)
return;
dialogResultAwaiter.SetResult(new DialogResult<string>(true));
}
In this way you can create your "own await" - which will "end" (and return results) when TaskComplectionSource.SetResult is called.

Image will not update in code only custom control inheriting from button in WPF

I am currently trying to build a custom button control for a dice game I am writing in WPF. Everything is working correctly except that the image in the UI while it is running does not change when the the die value has changed. I can confirm through my debug sessions that the image source is changing as expected as well as all values are changing as expected but the image just doesn't seem to want to update. I've tried looking over many similar questions but none of the questions seem to apply to my particular situation it would seem. I am new to WPF and not quite sure what I am doing wrong here... my current code is as follows:
using BluffersDice.GameEngine;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Media;
using System.Windows.Media.Imaging;
namespace BluffersDice.Interface.CustomControls
{
public class DieButton : Button
{
private Die _DieValue;
private readonly BitmapImage ONE_IMAGE = new BitmapImage(new Uri("/res/dice/1.png",UriKind.Relative));
private readonly BitmapImage TWO_IMAGE = new BitmapImage(new Uri("/res/dice/2.png", UriKind.Relative));
private readonly BitmapImage THREE_IMAGE = new BitmapImage(new Uri("/res/dice/3.png", UriKind.Relative));
private readonly BitmapImage FOUR_IMAGE = new BitmapImage(new Uri("/res/dice/4.png", UriKind.Relative));
private readonly BitmapImage FIVE_IMAGE = new BitmapImage(new Uri("/res/dice/5.png", UriKind.Relative));
private readonly BitmapImage SIX_IMAGE = new BitmapImage(new Uri("/res/dice/6.png", UriKind.Relative));
private const string HELD_LABEL_TEXT = "Held";
//private bool initcompleted = false;
private Label HoldLabel { get; set; }
public DieButton() : this(new Die())
{}
public DieButton(Die dieValue)
{
Background = Brushes.Transparent;
BorderBrush = new SolidColorBrush(Colors.Transparent);
BorderThickness = new Thickness(6);
HoldLabel = new Label() { MinHeight = 15 };
Click += This_OnClick;
DieValueChanged += DieValueChangedHandler;
dieValue.IsHeldChanged += DieValue_IsHeldChanged;
dieValue.DieValueChanged += DieValueChangedHandler;
_DieValue = dieValue;
Panel = new StackPanel()
{
Orientation = Orientation.Vertical,
Margin = new Thickness(8)
};
DieImage = new Image() { Source = GetDieImageSource() };
Panel.Children.Add(DieImage);
Panel.Children.Add(HoldLabel);
Content = Panel;
UpdateButtonContent();
//initcompleted = true;
}
private void This_OnClick(object sender, RoutedEventArgs e)
{
DieValue.ToggleHold();
}
public event EventHandler DieValueChanged;
public Die DieValue
{
get
{
return _DieValue;
}
set
{
_DieValue = value;
if (DieValueChanged != null)
{
DieValueChanged(this, new EventArgs());
}
}
}
private Image DieImage { get; set; }
private StackPanel Panel { get; set; }
private void DieValue_IsHeldChanged(object sender, EventArgs e)
{
var d = (Die)sender;
if (d.IsHeld)
{
BorderBrush = new SolidColorBrush(Colors.Yellow);
}
else
{
BorderBrush = new SolidColorBrush(Colors.Transparent);
}
HoldLabel.Content = DieValue.IsHeld ? HELD_LABEL_TEXT : string.Empty;
}
private void DieValueChangedHandler(object sender, EventArgs e)
{
DieImage.Source = GetDieImageSource();
UpdateButtonContent();
}
private ImageSource GetDieImageSource()
{
switch (DieValue.Value)
{
case 1:
return ONE_IMAGE;
case 2:
return TWO_IMAGE;
case 3:
return THREE_IMAGE;
case 4:
return FOUR_IMAGE;
case 5:
return FIVE_IMAGE;
case 6:
return SIX_IMAGE;
default:
return null;
}
}
private void UpdateButtonContent()
{
(Panel.Children[0] as Image).Source = GetDieImageSource();
}
}
}
Window Is being used on:
using BluffersDice.GameEngine;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
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 BluffersDice.Interface.CustomControls;
namespace BluffersDice.Interface
{
/// <summary>
/// Interaction logic for UserTurn.xaml
/// </summary>
public partial class PlayerTurn : Window
{
public Turn TurnState { get; set; }
private Roll CurrentRoll { get; set; }
public PlayerTurn()
{
CurrentRoll = new Roll();
InitializeComponent();
btn_Die1 = new DieButton(CurrentRoll.Dice[0]);
btn_Die2 = new DieButton(CurrentRoll.Dice[1]);
btn_Die3 = new DieButton(CurrentRoll.Dice[2]);
btn_Die4 = new DieButton(CurrentRoll.Dice[3]);
btn_Die5 = new DieButton(CurrentRoll.Dice[4]);
GameState.Caller.StartNewTurn();
TurnState = GameState.Caller.StartNewTurn();
lbl_PlayerTitle.Text = string.Format(lbl_PlayerTitle.Text, GameState.Caller.Id);
}
private void btn_DieValuechanged(object sender, EventArgs ea)
{
var d = (Die)sender;
MessageBox.Show(String.Format("Die Button {0} Value Changed To {1}", d.Id, d.Value));
}
private void DieValueChanged(object sender, EventArgs e)
{
var d = (Die)sender;
//MessageBox.Show(String.Format("Die {0} Value Changed To {1}", d.Id, d.Value));
}
private void RollDice_btnClick(object sender, RoutedEventArgs e)
{
CurrentRoll.RollDice();
}
}
}
Each time you want to change your image try doing the below
= new BitmapImage(new Uri(...
I have read around that usually works or you can follow the solution discussed here
http://social.msdn.microsoft.com/Forums/en/wpf/thread/976e8d89-aafd-4708-9e4f-87655a5da558

Categories

Resources