Get editor's OldValue from DevExpress RepositoryItemGridLookUpEdit in EditValueChanged event - winforms

I'm using the classic WinForms version of the DevExpress XtraEditors. The WPF version makes it easy to get the editor's old value in the EditValueChanged event, but I don't see how to get the old value in the WinForms counterpart EditValueChanged event. If it can be obtained from within that event, how to do it?
https://documentation.devexpress.com/#windowsforms/DevExpressXtraEditorsRepositoryRepositoryItem_EditValueChangedtopic

RepositoryItemGridLookUpEdit class is not an editor itself. This class is only holding properties for in-place editors. So, to get editor's old value you must get the editor itself (from sender object) and use its BaseEdit.OldEditValue property.
Here is example:
private void repositoryItemGridLookUpEdit1_EditValueChanged(object sender, EventArgs e)
{
var baseEdit = (BaseEdit)sender;
if (baseEdit.OldEditValue.ToString() == "Some value")
{
//...
}
}

Related

WPF Richtextbox Bindable in .net 4.5

So I'm trying to use David Veeneman's Bindable WPF RichTextBox here in my .net 4.5 project. After adding the control and the ValueConverter in my code I noticed only the the public object Convert() will be triggered but the public object ConvertBack() not.
After reading the comments to this project I changed following parts of the control source code.
private static void OnDocumentChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
var thisControl = (EcoRichTextBox)d;
if (thisControl.m_InternalUpdatePending > 0)
{
thisControl.m_InternalUpdatePending--;
return;
}
// Changed:
try
{
thisControl.TextBox.Document = (e.NewValue == null) ? new FlowDocument() : (FlowDocument)e.NewValue;
}
catch { }
thisControl.m_TextHasChanged = false;
}
And this Event Handler:
private void OnTextChanged(object sender, TextChangedEventArgs e)
{
// Set the TextChanged flag
m_TextHasChanged = true;
// Changed:
Document = TextBox.Document;
}
Now the the both method of the ValueConverter worked fine but events like private void OnNormalTextClick(object sender, RoutedEventArgs e) causes a FatalExecutionEngineError on Runtime.
So i wonder if there are major changes form WPF 3.5 to 4.5?
Or anybody have an idea to work around this?
Update
Binding in XAML
<uc:FsRichTextBox Margin="5"
Document="{Binding Path=Ereignis.Bericht,
Converter={StaticResource flowDocumentConverter},
UpdateSourceTrigger=PropertyChanged, NotifyOnSourceUpdated=True}" />
I ran the demo you linked here in VS2015 with target framework 4.0 and 4.5. It will not update when I take out the two way data binding.
Add to your RTB. Two way data binding and a name:
Mode=TwoWay
x:Name="EditBox"
I think rather than managing the text change yourself here, remove this:
// Changed:
Document = TextBox.Document;
Use an event handler to update the data.
Then in your event handler that is managing your updates (I am assuming a button click? And allow this to manage the update.
this.EditBox.UpdateDocumentBindings();
The x:name attribute is valuable.
This is all found in the source code.
If you can be more clear about how your project is arranged I can provide more detail. But for starters, I would do this. Stick more closely to the provided example.

WinForm text box: MenuStrip keyboard shortcuts overriding OS-level copy/paste

Update: I've figured out the source of the issue, now trying to figure out the best fix
I've got a Form with a customized MenuStrip, with all sorts of bells and whistles. Of note here, is that many of my MenuStrip items have keyboard shortcuts - namely ones for Cut/Copy/Paste.
It appears that the presence of this MenuStrip is overriding (and therefore cancelling) the default Cut/Copy/Paste keyboard shortcut behaviors for my text boxes (and other controls).
All of them.
.
I can't really say I have a reason for the MenuStrip Cut/Copy/Paste options, besides the fact that I would expect to see them there. That's how Office type programs operate, and it's something the user (myself included) would expect.
I could remove the Cut/Copy/Paste options from the MenuStrip, but that would be admitting defeat! So how do I keep my overly engineered MenuStrip from forcing me to implement custom code for EVERY control that's Cut/Copy/Paste friendly?
.
** Original Post: **I've got a TextBox control in a toolbar which is to be used throughout my program. Imagine my surprise when native OS-level Copy/Paste events were not supported by default.
Sure, I could code something manually, but when I right-click on the control, Cut/Copy/Paste are already built in. How can I leverage this existing functionality?
I figure adding a KeyDown event with Ctrl+C, P, and X would be about the maximum I should have to code. For those events I just call a built-in method or something. That, or find a setting that enables native cut/copy/paste.
What am I overlooking/missing?
Testing it out native copy and paste does work on a TextBox control unless you are overridding the ContextMenu or ContextMenuStrip, in that case you will need to use the ClipBoard Class to implement it yourself.
In looking at it further this MSDN Forum article discusses sending the Commands to the Native Textbox Control using the SendMessage Method. This is implemented in a Custom TextBox which sounds like what you are doing.
Small excerpt see article for further implementation:
protected void itemCut_Click(object sender, EventArgs e)
{
SendMessage(this.Handle, TextBoxMessages.WM_CUT, 0, 0);
}
public static class TextBoxMessages
{
public const int EM_UNDO = 0x00C7;
public const int WM_CUT = 0x0300;
public const int WM_COPY = 0x0301;
public const int WM_PASTE = 0x0302;
}
Easy Solution: Use the SendKeys.Send() call within the Click event.
SendKeys.Send("^X");
I'm doing something a little more complicated, so here's the details:
I'm making several Forms, which all share some custom controls: MenuStrip, StatusStrip, and a few other custom controls. I've decided to have the Forms all inherit from the same base class, to allow common implementation of lots of stuff.
public partial class CommonFormBase : Form
{
private void Initialize()
{
//Bind click event for custom MenuStrip to events in the local Form
CommonMenuStrip.Edit_Cut.Click += new EventHandler(Edit_Cut_Click);
CommonMenuStrip.Edit_Copy.Click += new EventHandler(Edit_Copy_Click);
CommonMenuStrip.Edit_Paste.Click += new EventHandler(Edit_Paste_Click);
}
//Implement Click events for the MenuStrip by calling local methods
internal void Edit_Cut_Click(object sender, EventArgs e) { Cut(); }
internal void Edit_Copy_Click(object sender, EventArgs e) { Copy(); }
internal void Edit_Paste_Click(object sender, EventArgs e) { Paste(); }
//Generic implementation of common commands for the CommonFormBase
public virtual void Cut() { SendKeys.Send("^X"); }
public virtual void Copy() { SendKeys.Send("^C"); }
public virtual void Paste() { SendKeys.Send("^V"); }
}
I implemented the MenuStrip's click event at the Form level (not the MenuStrip level), but in that event I only call a generic method, which does all the code. In this example it's overkill, but I have other MenuStrip commands that will change in functionality for different child Forms, so I figured having them all work the same would be easier.
Anyway, this works almost perfectly! It seems to push the shortcut-key-activated MenuStrip_Click event to the underlying control (or maybe the Form?), which then implements default shortcut key events.
The only thing it does wrong is it only triggers ONCE when you do Ctrl + V + V + V... or hold Ctrl+V. Still, that's just a matter of the trigger not recognizing multiple events, not an issue with the solution itself.

Override default value of TextBox.TextProperty

I have a custom control that derives from TextBox. And I cannot find a way to override the default Text value. So, in short - I want MyTextBox to have some specific default text in it.
The code:
public class MyTextBox : TextBox
{
static MyTextBox()
{
TextBox.TextProperty.OverrideMetadata(
typeof(MyTextBox),
new FrameworkPropertyMetadata("DEFAULT TEXT", OnTextChanged));
}
private static void OnTextChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
}
}
The problem is that the property (strangely) contains the "DEFAULT TEXT" value, yet it does not show up in the UI (text box is empty).
What am I doing wrong?
The TextBox uses an inner class to provide most of it's functionality. This same class is shared with RichTextBox. I believe the TextBox assumes Text will be empty when constructed, so the UI is not updated.
One thing to keep in mind is that you have effectively short-circuited the TextBox.OnTextPropertyChanged method from being called. If you want to override the PropertyChangedCallback, then you'd probably need to manually call the TextBox version to ensure everything works as expected.
You can get to the base class's PropertyChangedCallback using TextProperty.GetMetadata(typeof(TextBox)).PropertyChangedCallback.
You may be able to call the TextBox's PropertyChangedCallback in an instance constructor to force the UI to update. Otherwise, you'd need to set Text directly.

WPF UI Scenario - Best way to add a functionality in 50 views?

I want some suggestions to implement this functionality with a neat design and without any code replication. I have an application with many views and grid control in most of the views. I need to add an export functionality (export records to excel).The grid control supports this OOB, just need to call 'Grid.Export()'. I am planning a UI button on the side of every grid and call this method.
So, obviously I need to write the code in code-behind only since I need the control's instance to invoke the method. But, I like to keep the code in one place and somehow invoke the code from all Xamls. (all WPF views).
One technique is to write a BaseView class and derive all Views from this.
But would like to know if WPF suppots any techniques by which I can achieve this. (behaviours etc..?)
Thanks,
Mani
Create a UserControl that includes both the datagrid and the export button. In effect, make it part of the grid itself.
Use this UserControl instead of the default datagrid in all of your views, and you're done.
Furthermore, if you ever have to modify the look and feel of your button or its behaviour, you have only one place in which to change it, and it will be updated in all of your views.
One of solutions is to use WPF routed command.
Note: I wrote this answer with the assumption that your "View" is a subclass of Window class.
First, add a custom routed command to your project.
public static class MyCommands
{
private static readonly RoutedUICommand exportCommand = new RoutedUICommand("description", "Export", typeof(MyCommands));
public static RoutedUICommand ExportCommand
{
get
{
return exportCommand;
}
}
}
In each View, set your custom command to Button.Command and bind a target object to Button.CommandTarget.
<Button Command="local:MyCommands.ExportCommand" CommandTarget="{Binding ElementName=dataGrid1}">Export</Button>
Firnally, in your Application class (named App by default), register a command binding between your custom command and Window.
public partial class App : Application
{
public App()
{
var binding = new CommandBinding(MyCommands.ExportCommand, Export, CanExport);
CommandManager.RegisterClassCommandBinding(typeof(Window), binding);
}
private void Export(object sender, ExecutedRoutedEventArgs e)
{
// e.Source refers to the object is bound to Button.CommandTarget.
var dataGrid = (DataGrid)e.Source;
// Export data.
}
private void CanExport(object sender, CanExecuteRoutedEventArgs e)
{
// Assign true to e.CanExecute if your application can export data.
e.CanExecute = true;
}
}
Now, App.Export is invoked when user click a button.
Sample is available here.

WPF ComboBox DropDown part appears in the wrong place

I put several ComboBoxes on a XAML window. When I expand any of them, the DropDown part appears on the upper left corner of the screen.
I use Visual Studio 2008 C# Express. I don't remember this phenomenon when I used Visual Studio 2008 (Trial Version), though I use the same FrameWork (3.5).
It seems to be a bug.
Workaround:
Use Window.Show() instead with a custom logic to simulate the ShowDialog() behavior.
This appears to be a bug in WPF. In my case, I was trying to open a window in the Loaded event of another window. To get around this, I set a timer up to fire, then used a delegate to open the window (cannot open the window in a timer event because the calling thread that opens a window must be STA).
Edit - timer isn't necessary - didn't see the answer above just queue it on the dispatcher...
private delegate void DelegateOpenWindow();
private DelegateOpenWindow m_DelegateOpenWindow;
private Timer loginTimer = new Timer(200);
private void MainWindow1_Loaded(object sender, RoutedEventArgs e)
{
// create delegate used for asynchronous call
m_DelegateOpenWindow= new DelegateOpenWindow(this.OpenWindow);
// start a timer to fire off the open window.
loginTimer.Elapsed += loginTimer_Elapsed;
loginTimer.Enabled = true;
}
void loginTimer_Elapsed(object sender, ElapsedEventArgs e)
{
loginTimer.Enabled = false;
this.Dispatcher.BeginInvoke(m_DelegateOpenWindow);
}
void OpenWindow()
{
MyWindow w = new MyWindow();
w.Owner = this;
w.ShowDialog();
}
I started observing this (and other strange behavioral quirks) yesterday when I tried to "tweak" window sizes, shapes, colors, and invoke a log-on dialog from the Window.Loaded event handler. I had been doing this just fine in each of a dozen+ individual "MVVM" pattern apps. Yesterday, I decided to move this from each app's code behind into a consolidated code-behind base class, since the pre-processing had become common in all those apps. When I did, the drop-downs in two ComboBoxes in the log-in dialog suddenly appeared in the upper left corner of my screen. I seem to have "solved" it by using the following technique (your mileage may vary):
protected void WindowBaseLoadedHandler(object sender, RoutedEventArgs e)
{
...non-essential lines of code removed...
if (DataContext != null)
{
Dispatcher.BeginInvoke(DispatcherPriority.Normal, new Action(() =>
{
/*----------------------------------------------------------------------
* Do we have a View Model? If so, perform standard VM Initialization...
*---------------------------------------------------------------------*/
this.IsEnabled = false;
LoginDlg loginDlg = new LoginDlg();
loginDlg.ShowDialog();
if (!loginDlg.Success)
{
/*-----------------------------------
* Log on failed -- terminate app...
*----------------------------------*/
...termination logic removed...
}
this.IsEnabled = true;
}));
}
WindowBaseLoadedHandler is the Loaded event handler. LoginDlg is a WPF app with a dialog containing two ComboBoxes.
Recap: After I consolidated the code into the Loaded event handler of the base class the ComboBox's drop down lists appeared in the upper left corner of my screen. Once I wrapped the logic into the Dispatcher.BeginInvoke call, the appropriate ComboBox behavior returned with lists below the current item.
I suspect WPF needs the application to return from the Loaded event to complete the layout system's initialization. That doesn't fully explain why it worked before, but I'll have to queue up my desire to hunt that "why" down for some rainy day in the future and celebrate overcoming the latest obstacle for today.
In any event, I hope someone finds this of use.
I'm using the latest .Net 4.5 and WPF framework and I still have this problem. One thing I noticed is that it only happen when there's an attached debugger. When the debugger is not attached, everything works fine.
I had the same problem on Visual Studio 2019.
Using window.Show() can help but it can ruin your design.
The solution is to open the window asynchronously.
var yourDialog= new YourDialog();
yourDialog.Owner = this;
TaskCompletionSource<bool?> completion = new TaskCompletionSource<bool?>();
this.Dispatcher.BeginInvoke(new Action(() =>
completion.SetResult(yourDialog.ShowDialog())));
bool? result = await completion.Task;
You can also create a more elegant solution by making the extension method:
public static class AsyncWindowExtension
{
public static Task<bool?> ShowDialogAsync(this Window self)
{
if (self == null) throw new ArgumentNullException("self");
TaskCompletionSource<bool?> completion = new TaskCompletionSource<bool?>();
self.Dispatcher.BeginInvoke(new Action(() => completion.SetResult(self.ShowDialog())));
return completion.Task;
}
}
And you can use it like this:
await dlgReview.ShowDialogAsync();
It’s a bug in WPF (not the only one, I'm afraid). It happened when I opened another window in the Loaded Event, something like:
private void Window_Loaded(object sender, RoutedEventArgs e)
{
Window selectionWindow = new SelectionWindow();
bool? result = selectionWindow.ShowDialog();
if (result == true)
RecordChanged();
}
I already found a workabout.

Resources