How do I disable an action in a nested listview if there is no record? - xaf

I have a PopUpWindowShowAction that operates on the current record.
If there is no current record then I want the action disabled.
This is because if there is no record the PopUpWindowShowAction will fail.
Here is my simplified controller
using DevExpress.ExpressApp;
using DevExpress.ExpressApp.Actions;
using DevExpress.ExpressApp.Editors;
using System;
using System.Linq;
using System.Windows.Forms;
namespace MyNamespace
{
public partial class JobWorkflowController : ViewController
{
PopupWindowShowAction actWorkflow;
public JobWorkflowController()
{
TargetObjectType = typeof(IWorkflow);
actWorkflow = new PopupWindowShowAction(this, "Workflow", "Admin")
{ AcceptButtonCaption = string.Empty, ActionMeaning = ActionMeaning.Accept, CancelButtonCaption = null, Caption = "Workflow", ConfirmationMessage = null, ImageName = "Workflow", Shortcut = "F7", ToolTip = null };
actWorkflow.CustomizePopupWindowParams += actWorkflow_CustomizePopupWindowParams_1;
actWorkflow.Execute += actWorkflow_Execute_1;
actWorkflow.Cancel += actWorkflow_Cancel;
}
private void actWorkflow_CustomizePopupWindowParams_1(object sender, CustomizePopupWindowParamsEventArgs e)
{
if (View.CurrentObject is not IWorkflow wf)
{
// causes an error because the view is not set
return;
}
// code to create the popup view
}
private void actWorkflow_Execute_1(object sender, PopupWindowShowActionExecuteEventArgs e)
{
// code
}
private void actWorkflow_Cancel(object sender, EventArgs e)
{
// code
}
protected override void OnActivated()
{
base.OnActivated();
View.CurrentObjectChanged += View_CurrentObjectChanged;
View_CurrentObjectChanged(View, new EventArgs());
}
private void View_CurrentObjectChanged(object sender, EventArgs e)
{
actWorkflow.Enabled["HasCurrent"]= View.CurrentObject != null;
}
protected override void OnDeactivated()
{
View.CurrentObjectChanged -= View_CurrentObjectChanged;
base.OnDeactivated();
}
}
}
The View_CurrentObjectChanged event fires but the action does not disable.
[Update]
I tried Michael's suggestion but the action des not disable.

Put this in your constructor
actWorkflow.SelectionDependencyType = SelectionDependencyType.RequireSingleObject
And it will only be active when a single object is selected. If you'd like to have one or more objects selected it's:
actWorkflow.SelectionDependencyType = SelectionDependencyType.RequireMultipleObjects;
You'll have no need to subscribe to the CurrentObjectChanged event.

Related

How to approach writing a WPF Custom Control in F#?

I am trying to understand how a wpf custom control could be written in F#.
As an example, I have the following C# code for a drag and drop on a canvas (in C#). It inherits from ListBox. I'm not looking for anybody to rewrite this. But I'm at a loss as to how it would be implemented in Elmish.wpf since there is no xaml to deal with. (I believe a Custom Control does not have a XAML interface).
using System;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Input;
namespace Stargate.XI.Client.Views.CustomControls
{
public delegate void DropCompletedEventHandler(object sender, DropCompletedEventArgs e);
// To add a custom DropCompletedEvent to an ItemsControl, I would either have to have an attached property, as in
// https://stackoverflow.com/questions/15134514/attached-behavior-handling-an-attached-event-in-wpf
// or subclass an ItemsControl as below. Creating a simple custom control, like here, seems cleaner.
// Note: ItemsControl can't select items, only present collections. Only a Selector or one of it's descendants can select items
// Hence, only the ListBox or its derivative,ListView, have Selector's.
public class ChartCanvas : ListBox
{
public event EventHandler PlayMusicEvent;
public event EventHandler PauseMusicEvent;
public event EventHandler StopMusicEvent;
public event EventHandler DisposeMusicEvent;
public event EventHandler DisposePosterEvent;
#region DropCompletedEvent
// Create a custom routed event by first registering a RoutedEventID
// This event uses the bubbling routing strategy
public static readonly RoutedEvent DropCompletedEvent = EventManager.RegisterRoutedEvent(
"DropCompleted", RoutingStrategy.Bubble, typeof(DropCompletedEventHandler), typeof(ChartCanvas));
// Provide CLR accessors for the event. The RoutedEventHandler, e.g., "DropCompleted" is used in the xaml declaration for the ImageCanvas.
public event DropCompletedEventHandler DropCompleted
{
add { AddHandler(DropCompletedEvent, value); }
remove { RemoveHandler(DropCompletedEvent, value); }
}
// This method raises the DropCompleted event
public void RaiseDropCompletedEvent(object datatype)
{
RaiseEvent(new DropCompletedEventArgs(DropCompletedEvent, datatype));
}
#endregion
public ChartCanvas()
{
AllowDrop = true;
DragEnter += IC_DragEnter;
Drop += IC_Drop;
DragOver += IC_DragOver;
DragLeave += IC_DragLeave;
}
private void IC_DragLeave(object sender, DragEventArgs e)
{
e.Handled = true;
}
private void IC_DragOver(object sender, DragEventArgs e)
{
e.Handled = true;
}
private void IC_Drop(object sender, DragEventArgs e)
{
var data = e.Data.GetData(DataFormats.Text);
var dragSource = e.Data.GetData("DragSource");
RaiseDropCompletedEvent(data);
}
private void IC_DragEnter(object sender, DragEventArgs e)
{
e.Handled = true;
}
#region PlayMovie
private ICommand _playMovie;
public ICommand PlayMovieCommand
{
get
{
if (_playMovie == null)
{
_playMovie = new RelayCommand(
p => true,
p => this.PlayMovie());
}
return _playMovie;
}
}
private void PlayMovie()
{
PlayMusicEvent?.Invoke(this, EventArgs.Empty);
}
#endregion
#region PauseMovie
private ICommand _pauseMovie;
public ICommand PauseMovieCommand
{
get
{
if (_pauseMovie == null)
{
_pauseMovie = new RelayCommand(
p => true,
p => this.PauseMovie());
}
return _pauseMovie;
}
}
private void PauseMovie()
{
PauseMusicEvent?.Invoke(this, EventArgs.Empty);
}
#endregion
#region StopMovie
private ICommand _stopMovie;
public ICommand StopMovieCommand
{
get
{
if (_stopMovie == null)
{
_stopMovie = new RelayCommand(
p => true,
p => this.StopMovie());
}
return _stopMovie;
}
}
private void StopMovie()
{
StopMusicEvent?.Invoke(this, EventArgs.Empty);
}
#endregion
public bool Dispose
{
get { return (bool)GetValue(DisposeProperty); }
set { SetValue(DisposeProperty, value); }
}
// Using a DependencyProperty as the backing store for Dispose. This enables animation, styling, binding, etc...
public static readonly DependencyProperty DisposeProperty =
DependencyProperty.Register("Dispose", typeof(bool), typeof(ChartCanvas), new PropertyMetadata(false,
(s,e) =>
{
ChartCanvas chartcanvas = s as ChartCanvas;
chartcanvas.DisposeMusicEvent?.Invoke(chartcanvas, EventArgs.Empty);
chartcanvas.DisposePosterEvent?.Invoke(chartcanvas, EventArgs.Empty);
}
));
}
}
Any suggestions to this newbie as to how to approach this would be much appreciated.
TIA

Xamarin Forms iOS CustomRenderer not repainting

I have a custom renderer to display HTML formatted text in a UITextView. If I hard-code the text into the constructor of the page that contains the control (so it gets set in the custom control's OnElementChanged event), it displays fine. If I await a api call to get the text and then set it (so it gets set in the custom control's OnElementPropertyChanged event) it does not repaint. If I change the orientation of the device, the text appears. What do I need to add to get it to display the text when it is set?
[assembly: ExportRenderer(typeof(HtmlLabel), typeof(HtmlLabelRenderer))]
namespace MyApp.iOS.Renderers
{
class HtmlLabelRenderer : ViewRenderer<HtmlLabel, UITextView>
{
private UITextView _htmlTextView = new UITextView();
protected override void OnElementChanged(ElementChangedEventArgs<HtmlLabel> e)
{
base.OnElementChanged(e);
if (Element?.Text == null) return;
SetHtmlText(Element.Text);
}
protected override void OnElementPropertyChanged(object sender, PropertyChangedEventArgs e)
{
if (string.Equals(e.PropertyName, "Text", StringComparison.CurrentCultureIgnoreCase))
{
SetHtmlText(((HtmlLabel)sender).Text);
_htmlTextView.SetNeedsDisplay();
}
base.OnElementPropertyChanged(sender, e);
}
private void SetHtmlText(string text)
{
var attr = new NSAttributedStringDocumentAttributes {DocumentType = NSDocumentType.HTML};
var nsError = new NSError();
_htmlTextView.Editable = false;
_htmlTextView.AttributedText = new NSAttributedString(text, attr, ref nsError);
_htmlTextView.DataDetectorTypes = UIDataDetectorType.All;
SetNativeControl(_htmlTextView);
}
}
}
Update : I got further by changing the OnElementChanged to:
protected override void OnElementChanged(ElementChangedEventArgs<HtmlLabel> e)
{
base.OnElementChanged(e);
if (e.OldElement != null || Element == null) return;
SetHtmlText(e.NewElement.Text ?? string.Empty);
SetNativeControl(_htmlTextView);
}
now if I have more than one HtmlLabel on the page all except the first one displays.
Try changing from:
_htmlTextView.SetNeedsDisplay();
to
SetNeedsDisplay();
or,
(Control ?? NativeView).SetNeedsDisplay();
Sharada Gururaj is right, changing to derive from Editor worked for iOS .. but breaks Android. Though this seems brute force, I used conditional compilation to get it working...
namespace MyApp.Renderers
{
#if __IOS__
public class HtmlLabel : Editor
{
}
#else
public class HtmlLabel : Label
{
}
#endif
}
Here is the android
[assembly: ExportRenderer(typeof(HtmlLabel), typeof(HtmlLabelRenderer))]
namespace MyApp.Droid.Renderers
{
public class HtmlLabelRenderer : LabelRenderer
{
protected override void OnElementChanged(ElementChangedEventArgs<Label> e)
{
base.OnElementChanged(e);
var view = (HtmlLabel)Element;
if (view?.Text == null) return;
SetHtmlText(view.Text);
}
protected override void OnElementPropertyChanged(object sender, PropertyChangedEventArgs e)
{
base.OnElementPropertyChanged(sender, e);
if (e.PropertyName == Label.TextProperty.PropertyName)
{
SetHtmlText(((HtmlLabel) sender).Text);
}
}
private void SetHtmlText(string text)
{
var encodedText = (((int)Build.VERSION.SdkInt) >= 24) ? Html.FromHtml(text, FromHtmlOptions.ModeLegacy) :
#pragma warning disable 618
// need this for backward compatability
Html.FromHtml(text);
#pragma warning restore 618
Control.MovementMethod = LinkMovementMethod.Instance;
Control.SetText(encodedText, TextView.BufferType.Spannable);
}
}
}
Your custom HtmlLabel class should be able to derive from the same thing on Android and iOS
namespace YourNameSpace
{
public class HtmlLabel : Label
{
}
}
The renderer for Android should look something like this
[assembly: ExportRenderer(typeof(HtmlLabel), typeof(HtmlLabelRenderer))]
namespace YourNameSpace.Droid
{
public class HtmlLabelRenderer : ViewRenderer<Label, TextView>
{
TextView _textView;
protected override void OnElementChanged(ElementChangedEventArgs<Label> e)
{
base.OnElementChanged(e);
if (Element == null)
return;
if(Control == null)
{
_textView = new TextView(Context);
SetHtmlText(Element.Text);
SetNativeControl(_textView);
}
}
protected override void OnElementPropertyChanged(object sender, PropertyChangedEventArgs e)
{
base.OnElementPropertyChanged(sender, e);
if (Element == null || Control == null)
return;
if (e.PropertyName == HtmlLabel.TextProperty.PropertyName)
{
SetHtmlText(Element.Text);
}
}
private void SetHtmlText(string text)
{
if (Android.OS.Build.VERSION.SdkInt >= BuildVersionCodes.N)
{
_textView.TextFormatted = Html.FromHtml(text, Android.Text.FromHtmlOptions.ModeCompact);
}
else
{
_textView.TextFormatted = Html.FromHtml(text);
}
}
}
}
And on iOS it should look very similar
[assembly: ExportRenderer(typeof(HtmlLabel), typeof(HtmlLabelRenderer))]
namespace YourNameSpace.iOS
{
public class HtmlLabelRenderer : ViewRenderer<Label, UITextView>
{
UITextView _textView;
protected override void OnElementChanged(ElementChangedEventArgs<Label> e)
{
base.OnElementChanged(e);
if (Element == null)
return;
if(Control == null)
{
_textView = new UITextView();
SetHtmlText(Element.Text);
SetNativeControl(_textView);
}
}
protected override void OnElementPropertyChanged(object sender, PropertyChangedEventArgs e)
{
base.OnElementPropertyChanged(sender, e);
if (Element == null || Control == null)
return;
if (e.PropertyName == HtmlLabel.TextProperty.PropertyName)
{
SetHtmlText(Element.Text);
}
}
private void SetHtmlText(string text)
{
var attr = new NSAttributedStringDocumentAttributes { DocumentType = NSDocumentType.HTML };
var nsError = new NSError();
_textView.Editable = false;
_textView.AttributedText = new NSAttributedString(text, attr, ref nsError);
_textView.DataDetectorTypes = UIDataDetectorType.All;
}
}
}
I tested that on Android and it worked, calling OnElementPropertyChanged when the text changed and everything. However, I don't have a mac at home to try the iOS Renderer so I'm just assuming it will function pretty much the same.

Recycler view notifyDataSetChange not working from custom adapter

I have a customer list. First time it renders with all customers, then I added a filter to list only new customers. Modified the source items with new customers. But it is not rendering in the view. Adapter constructor is called with new set of array. But it is not invoking the method public override int ItemCount. This page will get rendered on screen lock and unlock of device. Please help me here
public class RecyclerViewRenderer : ViewRenderer<RecyclerViewList, RecyclerView>
{
.........
protected override void OnElementPropertyChanged(object sender, System.ComponentModel.PropertyChangedEventArgs e)
{
base.OnElementPropertyChanged(sender, e);
if (e.PropertyName == RecyclerViewList.ItemsProperty.PropertyName)
{
var items = (Element as RecyclerViewList).Items;
if (items != null)
{
adapter = new RecyclerViewAdapter(items);
adapter.ItemClickEvent += OnItemClick;
adapter.PopUpClickEvent += OnPopUpClick;
recyclerViewCustomers.SetAdapter(adapter);
adapter.NotifyDataSetChanged();
// Task.Delay(500);
}
}
}
......
}

Make two ListBoxes scroll together

I wish to make two ListBoxes scroll together.
I have two ListBoxes of the same height with the same number of items, etc. I want to set it up such that if the user scrolls up/down in one list box the scrollbar for the other ListBox scrolls up/down as well.
But I can not seem to find a way to either detect the scroll bar position value or to detect when it has changed value.
Here is another way to sync the two ListBoxes:
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
namespace SyncTwoListBox
{
public partial class Form1 : Form
{
private SyncListBoxes _SyncListBoxes = null;
public Form1()
{
InitializeComponent();
this.Load += Form1_Load;
//add options
for (int i = 0; i < 40; i++)
{
listBox1.Items.Add("Item " + i);
listBox2.Items.Add("Item " + i);
}
}
private void Form1_Load(object sender, EventArgs e)
{
this._SyncListBoxes = new SyncListBoxes(this.listBox1, this.listBox2);
}
}
public class SyncListBoxes
{
private ListBox _LB1 = null;
private ListBox _LB2 = null;
private ListBoxScroll _ListBoxScroll1 = null;
private ListBoxScroll _ListBoxScroll2 = null;
public SyncListBoxes(ListBox LB1, ListBox LB2)
{
if (LB1 != null && LB1.IsHandleCreated && LB2 != null && LB2.IsHandleCreated &&
LB1.Items.Count == LB2.Items.Count && LB1.Height == LB2.Height)
{
this._LB1 = LB1;
this._ListBoxScroll1 = new ListBoxScroll(LB1);
this._ListBoxScroll1.Scroll += _ListBoxScroll1_VerticalScroll;
this._LB2 = LB2;
this._ListBoxScroll2 = new ListBoxScroll(LB2);
this._ListBoxScroll2.Scroll += _ListBoxScroll2_VerticalScroll;
this._LB1.SelectedIndexChanged += _LB1_SelectedIndexChanged;
this._LB2.SelectedIndexChanged += _LB2_SelectedIndexChanged;
}
}
private void _LB1_SelectedIndexChanged(object sender, EventArgs e)
{
if (this._LB2.TopIndex != this._LB1.TopIndex)
{
this._LB2.TopIndex = this._LB1.TopIndex;
}
if (this._LB2.SelectedIndex != this._LB1.SelectedIndex)
{
this._LB2.SelectedIndex = this._LB1.SelectedIndex;
}
}
private void _LB2_SelectedIndexChanged(object sender, EventArgs e)
{
if (this._LB1.TopIndex != this._LB2.TopIndex)
{
this._LB1.TopIndex = this._LB2.TopIndex;
}
if (this._LB1.SelectedIndex != this._LB2.SelectedIndex)
{
this._LB1.SelectedIndex = this._LB2.SelectedIndex;
}
}
private void _ListBoxScroll1_VerticalScroll(ListBox LB)
{
if (this._LB2.TopIndex != this._LB1.TopIndex)
{
this._LB2.TopIndex = this._LB1.TopIndex;
}
}
private void _ListBoxScroll2_VerticalScroll(ListBox LB)
{
if (this._LB1.TopIndex != this._LB2.TopIndex)
{
this._LB1.TopIndex = this._LB2.TopIndex;
}
}
private class ListBoxScroll : NativeWindow
{
private ListBox _LB = null;
private const int WM_VSCROLL = 0x115;
private const int WM_MOUSEWHEEL = 0x20a;
public event dlgListBoxScroll Scroll;
public delegate void dlgListBoxScroll(ListBox LB);
public ListBoxScroll(ListBox LB)
{
this._LB = LB;
this.AssignHandle(LB.Handle);
}
protected override void WndProc(ref Message m)
{
base.WndProc(ref m);
switch (m.Msg)
{
case WM_VSCROLL:
case WM_MOUSEWHEEL:
if (this.Scroll != null)
{
this.Scroll(_LB);
}
break;
}
}
}
}
}
enter image description here

DevExpress mvc extension :How to bind a object to DashboardSourceModel in asp.net mvc5

I am following the loading event of dashboard,but can not able to deploy this in my project.Can anyone help me to find the right approach.
Here is my controller
public ActionResult Demo()
{
return View();
}
[ValidateInput(false)]
public ActionResult DemoDashboardViewerPartial()
{
return PartialView("_DemoDashboardViewerPartial", DemoDashboardViewerSettings.Model);
}
public FileStreamResult DemoDashboardViewerPartialExport()
{
return DashboardViewerExtension.Export("DemoDashboardViewer", DemoDashboardViewerSettings.Model);
}
class DemoDashboardViewerSettings
{
public static DashboardSourceModel Model
{
get
{
return DashboardSourceModel();
}
}
private static DashboardSourceModel DashboardSourceModel()
{
DashboardSourceModel model = new DashboardSourceModel();
model.DashboardSource = typeof(IDBOWeb.Code.Dashboards.Dashboard1);
return model;
}
}
I am trying to add a pie item to dashboard by adding data source through binding the object and passes the arguments and values to pie item.
Here is my dashboard1.cs:
namespace IDBOWeb.Code.Dashboards
{
public partial class Dashboard1 : DevExpress.DashboardCommon.Dashboard
{
public Dashboard1()
{
InitializeComponent();
}
private void Dashboard1_DashboardLoading(object sender, EventArgs e)
{
Dashboard dashboard = new Dashboard();
var data = new suggestReport().GetData();
dashboard.AddDataSource("Data Source 1",data);
PieDashboardItem pie = new PieDashboardItem();
pie.DataSource = dashboard.DataSources[0];
pie.Arguments.Add(new Dimension("Russia"));
pie.Values.Add(new Measure("Open"));
pie.Values.Add(new Measure("Closed"));
dashboard.Items.Add(pie);
//pieDashboardItem1.Dashboard = dashboard;
}
private void Dashboard1_DataLoading(object sender, DashboardDataLoadingEventArgs e)
{
e.Data = new suggestReport().GetData();
}
}
}
finally it's working by doing following.
namespace IDBOWeb.Code.Dashboards
{
public partial class Dashboard1 : DevExpress.DashboardCommon.Dashboard
{
public Dashboard1()
{
InitializeComponent();
}
private void Dashboard1_DataLoading(object sender, DashboardDataLoadingEventArgs e)
{
e.Data = GetUserSessionCount(); //use a private function returning a list of object
}
private List<DashBoardUserSessionDetails> GetUserSessionCount()
{
List<DashBoardUserSessionDetails> userList = proxy.GetUserSessionCounts();//get the listed object
return userList;
}
}
}

Resources